HHH-7757 - NOT IN row-value syntax ignores NOT
This commit is contained in:
parent
9ec6eedca8
commit
08e63ac4a8
|
@ -23,6 +23,8 @@
|
|||
*/
|
||||
package org.hibernate.hql.internal.ast.tree;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import antlr.SemanticException;
|
||||
import antlr.collections.AST;
|
||||
|
||||
|
@ -191,9 +193,7 @@ public class BinaryLogicOperatorNode extends HqlSqlWalkerNode implements BinaryO
|
|||
protected static String[] extractMutationTexts(Node operand, int count) {
|
||||
if ( operand instanceof ParameterNode ) {
|
||||
String[] rtn = new String[count];
|
||||
for ( int i = 0; i < count; i++ ) {
|
||||
rtn[i] = "?";
|
||||
}
|
||||
Arrays.fill( rtn, "?" );
|
||||
return rtn;
|
||||
}
|
||||
else if ( operand.getType() == HqlSqlTokenTypes.VECTOR_EXPR ) {
|
||||
|
|
|
@ -121,50 +121,70 @@ public class InLogicOperatorNode extends BinaryLogicOperatorNode implements Bina
|
|||
|| ( !ParameterNode.class.isInstance( getLeftHandOperand() ) ) ? null
|
||||
: ( (ParameterNode) getLeftHandOperand() )
|
||||
.getHqlParameterSpecification();
|
||||
|
||||
final boolean negated = getType() == HqlSqlTokenTypes.NOT_IN;
|
||||
|
||||
if ( rhsNode != null && rhsNode.getNextSibling() == null ) {
|
||||
/**
|
||||
* only one element in "in" cluster, e.g.
|
||||
* only one element in the vector grouping.
|
||||
* <code> where (a,b) in ( (1,2) ) </code> this will be mutated to
|
||||
* <code>where a=1 and b=2 </code>
|
||||
*/
|
||||
if ( rhsNode != null && rhsNode.getNextSibling() == null ) {
|
||||
String[] rhsElementTexts = extractMutationTexts( rhsNode,
|
||||
rhsColumnSpan );
|
||||
setType( HqlSqlTokenTypes.AND );
|
||||
setText( "AND" );
|
||||
ParameterSpecification rhsEmbeddedCompositeParameterSpecification = rhsNode == null
|
||||
|| ( !ParameterNode.class.isInstance( rhsNode ) ) ? null
|
||||
: ( (ParameterNode) rhsNode )
|
||||
.getHqlParameterSpecification();
|
||||
translate( lhsColumnSpan, HqlSqlTokenTypes.EQ, "=", lhsElementTexts,
|
||||
String[] rhsElementTexts = extractMutationTexts( rhsNode, rhsColumnSpan );
|
||||
setType( negated ? HqlTokenTypes.OR : HqlSqlTokenTypes.AND );
|
||||
setText( negated ? "or" : "and" );
|
||||
ParameterSpecification rhsEmbeddedCompositeParameterSpecification =
|
||||
rhsNode == null || ( !ParameterNode.class.isInstance( rhsNode ) )
|
||||
? null
|
||||
: ( (ParameterNode) rhsNode ).getHqlParameterSpecification();
|
||||
translate(
|
||||
lhsColumnSpan,
|
||||
negated ? HqlSqlTokenTypes.NE : HqlSqlTokenTypes.EQ,
|
||||
negated ? "<>" : "=",
|
||||
lhsElementTexts,
|
||||
rhsElementTexts,
|
||||
lhsEmbeddedCompositeParameterSpecification,
|
||||
rhsEmbeddedCompositeParameterSpecification, this );
|
||||
} else {
|
||||
rhsEmbeddedCompositeParameterSpecification,
|
||||
this
|
||||
);
|
||||
}
|
||||
else {
|
||||
List andElementsNodeList = new ArrayList();
|
||||
while ( rhsNode != null ) {
|
||||
String[] rhsElementTexts = extractMutationTexts( rhsNode,
|
||||
rhsColumnSpan );
|
||||
AST and = getASTFactory().create( HqlSqlTokenTypes.AND, "AND" );
|
||||
ParameterSpecification rhsEmbeddedCompositeParameterSpecification = rhsNode == null
|
||||
|| ( !ParameterNode.class.isInstance( rhsNode ) ) ? null
|
||||
: ( (ParameterNode) rhsNode )
|
||||
.getHqlParameterSpecification();
|
||||
translate( lhsColumnSpan, HqlSqlTokenTypes.EQ, "=",
|
||||
lhsElementTexts, rhsElementTexts,
|
||||
String[] rhsElementTexts = extractMutationTexts( rhsNode, rhsColumnSpan );
|
||||
AST group = getASTFactory().create(
|
||||
negated ? HqlSqlTokenTypes.OR : HqlSqlTokenTypes.AND,
|
||||
negated ? "or" : "and"
|
||||
);
|
||||
ParameterSpecification rhsEmbeddedCompositeParameterSpecification =
|
||||
rhsNode == null || ( !ParameterNode.class.isInstance( rhsNode ) )
|
||||
? null
|
||||
: ( (ParameterNode) rhsNode ).getHqlParameterSpecification();
|
||||
translate(
|
||||
lhsColumnSpan,
|
||||
negated ? HqlSqlTokenTypes.NE : HqlSqlTokenTypes.EQ,
|
||||
negated ? "<>" : "=",
|
||||
lhsElementTexts,
|
||||
rhsElementTexts,
|
||||
lhsEmbeddedCompositeParameterSpecification,
|
||||
rhsEmbeddedCompositeParameterSpecification, and );
|
||||
andElementsNodeList.add( and );
|
||||
rhsEmbeddedCompositeParameterSpecification,
|
||||
group
|
||||
);
|
||||
andElementsNodeList.add( group );
|
||||
rhsNode = (Node) rhsNode.getNextSibling();
|
||||
}
|
||||
setType( HqlSqlTokenTypes.OR );
|
||||
setText( "OR" );
|
||||
setType( negated ? HqlSqlTokenTypes.AND : HqlSqlTokenTypes.OR );
|
||||
setText( negated ? "and" : "or" );
|
||||
AST curNode = this;
|
||||
for ( int i = andElementsNodeList.size() - 1; i > 1; i-- ) {
|
||||
AST or = getASTFactory().create( HqlSqlTokenTypes.OR, "OR" );
|
||||
curNode.setFirstChild( or );
|
||||
curNode = or;
|
||||
AST group = getASTFactory().create(
|
||||
negated ? HqlSqlTokenTypes.AND : HqlSqlTokenTypes.OR,
|
||||
negated ? "and" : "or"
|
||||
);
|
||||
curNode.setFirstChild( group );
|
||||
curNode = group;
|
||||
AST and = (AST) andElementsNodeList.get( i );
|
||||
or.setNextSibling( and );
|
||||
group.setNextSibling( and );
|
||||
}
|
||||
AST node0 = (AST) andElementsNodeList.get( 0 );
|
||||
AST node1 = (AST) andElementsNodeList.get( 1 );
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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.hql;
|
||||
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
import org.hibernate.engine.query.spi.HQLQueryPlan;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-7757" )
|
||||
public class TupleSupportTest extends BaseUnitTestCase {
|
||||
@Entity( name = "TheEntity" )
|
||||
public static class TheEntity {
|
||||
@Id
|
||||
private Long id;
|
||||
@Embedded
|
||||
private TheComposite compositeValue;
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public static class TheComposite {
|
||||
private String thing1;
|
||||
private String thing2;
|
||||
|
||||
public TheComposite() {
|
||||
}
|
||||
|
||||
public TheComposite(String thing1, String thing2) {
|
||||
this.thing1 = thing1;
|
||||
this.thing2 = thing2;
|
||||
}
|
||||
}
|
||||
|
||||
private SessionFactory sessionFactory;
|
||||
|
||||
@Before
|
||||
public void buildSessionFactory() {
|
||||
Configuration cfg = new Configuration()
|
||||
.addAnnotatedClass( TheEntity.class );
|
||||
cfg.getProperties().put( AvailableSettings.DIALECT, NoTupleSupportDialect.class.getName() );
|
||||
cfg.getProperties().put( AvailableSettings.HBM2DDL_AUTO, "create-drop" );
|
||||
sessionFactory = cfg.buildSessionFactory();
|
||||
}
|
||||
|
||||
@After
|
||||
public void releaseSessionFactory() {
|
||||
sessionFactory.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImplicitTupleNotEquals() {
|
||||
final String hql = "from TheEntity e where e.compositeValue <> :p1";
|
||||
HQLQueryPlan queryPlan = ( (SessionFactoryImplementor) sessionFactory ).getQueryPlanCache()
|
||||
.getHQLQueryPlan( hql, false, Collections.emptyMap() );
|
||||
|
||||
assertEquals( 1, queryPlan.getSqlStrings().length );
|
||||
System.out.println( " SQL : " + queryPlan.getSqlStrings()[0] );
|
||||
assertTrue( queryPlan.getSqlStrings()[0].contains( "<>" ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImplicitTupleNotInList() {
|
||||
final String hql = "from TheEntity e where e.compositeValue not in (:p1,:p2)";
|
||||
HQLQueryPlan queryPlan = ( (SessionFactoryImplementor) sessionFactory ).getQueryPlanCache()
|
||||
.getHQLQueryPlan( hql, false, Collections.emptyMap() );
|
||||
|
||||
assertEquals( 1, queryPlan.getSqlStrings().length );
|
||||
System.out.println( " SQL : " + queryPlan.getSqlStrings()[0] );
|
||||
assertTrue( queryPlan.getSqlStrings()[0].contains( "<>" ) );
|
||||
}
|
||||
|
||||
public static class NoTupleSupportDialect extends H2Dialect {
|
||||
@Override
|
||||
public boolean supportsRowValueConstructorSyntax() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsRowValueConstructorSyntaxInInList() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue