[hibernate-commits] Hibernate SVN: r14097 - in core/branches/Branch_3_2: src/org/hibernate/hql/ast/tree and 1 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Wed Oct 17 16:59:49 EDT 2007


Author: steve.ebersole at jboss.com
Date: 2007-10-17 16:59:49 -0400 (Wed, 17 Oct 2007)
New Revision: 14097

Added:
   core/branches/Branch_3_2/src/org/hibernate/hql/ast/tree/AbstractNullnessCheckNode.java
   core/branches/Branch_3_2/src/org/hibernate/hql/ast/tree/IsNotNullLogicOperatorNode.java
   core/branches/Branch_3_2/src/org/hibernate/hql/ast/tree/IsNullLogicOperatorNode.java
Modified:
   core/branches/Branch_3_2/src/org/hibernate/hql/ast/SqlASTFactory.java
   core/branches/Branch_3_2/src/org/hibernate/hql/ast/tree/UnaryLogicOperatorNode.java
   core/branches/Branch_3_2/test/org/hibernate/test/hql/ASTParserLoadingTest.java
Log:
HHH-2826 : (HQL) <component> is [not] null

Modified: core/branches/Branch_3_2/src/org/hibernate/hql/ast/SqlASTFactory.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/hql/ast/SqlASTFactory.java	2007-10-17 20:59:18 UTC (rev 14096)
+++ core/branches/Branch_3_2/src/org/hibernate/hql/ast/SqlASTFactory.java	2007-10-17 20:59:49 UTC (rev 14097)
@@ -1,13 +1,18 @@
 // $Id$
 package org.hibernate.hql.ast;
 
+import java.lang.reflect.Constructor;
+
 import antlr.ASTFactory;
 import antlr.Token;
 import antlr.collections.AST;
+
 import org.hibernate.hql.antlr.HqlSqlTokenTypes;
 import org.hibernate.hql.ast.tree.AggregateNode;
+import org.hibernate.hql.ast.tree.BetweenOperatorNode;
 import org.hibernate.hql.ast.tree.BinaryArithmeticOperatorNode;
 import org.hibernate.hql.ast.tree.BinaryLogicOperatorNode;
+import org.hibernate.hql.ast.tree.BooleanLiteralNode;
 import org.hibernate.hql.ast.tree.Case2Node;
 import org.hibernate.hql.ast.tree.CaseNode;
 import org.hibernate.hql.ast.tree.CollectionFunction;
@@ -19,10 +24,14 @@
 import org.hibernate.hql.ast.tree.FromElement;
 import org.hibernate.hql.ast.tree.IdentNode;
 import org.hibernate.hql.ast.tree.ImpliedFromElement;
+import org.hibernate.hql.ast.tree.InLogicOperatorNode;
 import org.hibernate.hql.ast.tree.IndexNode;
 import org.hibernate.hql.ast.tree.InitializeableNode;
 import org.hibernate.hql.ast.tree.InsertStatement;
 import org.hibernate.hql.ast.tree.IntoClause;
+import org.hibernate.hql.ast.tree.IsNotNullLogicOperatorNode;
+import org.hibernate.hql.ast.tree.IsNullLogicOperatorNode;
+import org.hibernate.hql.ast.tree.JavaConstantNode;
 import org.hibernate.hql.ast.tree.LiteralNode;
 import org.hibernate.hql.ast.tree.MethodNode;
 import org.hibernate.hql.ast.tree.OrderByClause;
@@ -30,19 +39,13 @@
 import org.hibernate.hql.ast.tree.QueryNode;
 import org.hibernate.hql.ast.tree.SelectClause;
 import org.hibernate.hql.ast.tree.SelectExpressionImpl;
+import org.hibernate.hql.ast.tree.SessionFactoryAwareNode;
 import org.hibernate.hql.ast.tree.SqlFragment;
 import org.hibernate.hql.ast.tree.SqlNode;
 import org.hibernate.hql.ast.tree.UnaryArithmeticNode;
+import org.hibernate.hql.ast.tree.UnaryLogicOperatorNode;
 import org.hibernate.hql.ast.tree.UpdateStatement;
-import org.hibernate.hql.ast.tree.BetweenOperatorNode;
-import org.hibernate.hql.ast.tree.UnaryLogicOperatorNode;
-import org.hibernate.hql.ast.tree.InLogicOperatorNode;
-import org.hibernate.hql.ast.tree.JavaConstantNode;
-import org.hibernate.hql.ast.tree.SessionFactoryAwareNode;
-import org.hibernate.hql.ast.tree.BooleanLiteralNode;
 
-import java.lang.reflect.Constructor;
-
 /**
  * Custom AST factory the intermediate tree that causes ANTLR to create specialized
  * AST nodes, given the AST node type (from HqlSqlTokenTypes).   HqlSqlWalker registers
@@ -157,7 +160,9 @@
 			case NOT_BETWEEN:
 				return BetweenOperatorNode.class;
 			case IS_NULL:
+				return IsNullLogicOperatorNode.class;
 			case IS_NOT_NULL:
+				return IsNotNullLogicOperatorNode.class;
 			case EXISTS:
 				return UnaryLogicOperatorNode.class;
 			default:

Added: core/branches/Branch_3_2/src/org/hibernate/hql/ast/tree/AbstractNullnessCheckNode.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/hql/ast/tree/AbstractNullnessCheckNode.java	                        (rev 0)
+++ core/branches/Branch_3_2/src/org/hibernate/hql/ast/tree/AbstractNullnessCheckNode.java	2007-10-17 20:59:49 UTC (rev 14097)
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
+ *
+ * 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, v. 2.1. This program is distributed in the
+ * hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
+ * distribution; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Red Hat Author(s): Steve Ebersole
+ */
+package org.hibernate.hql.ast.tree;
+
+import antlr.collections.AST;
+
+import org.hibernate.type.Type;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.hql.antlr.HqlSqlTokenTypes;
+import org.hibernate.util.StringHelper;
+import org.hibernate.HibernateException;
+
+/**
+ * AbstractNullnessCheckNode implementation
+ *
+ * @author Steve Ebersole
+ */
+public abstract class AbstractNullnessCheckNode extends UnaryLogicOperatorNode {
+	public void initialize() {
+		// TODO : this really needs to be delayed unitl after we definitively know the operand node type;
+		// where this is currently a problem is parameters for which where we cannot unequivocally
+		// resolve an expected type
+		Type operandType = extractDataType( getOperand() );
+		if ( operandType == null ) {
+			return;
+		}
+		SessionFactoryImplementor sessionFactory = getSessionFactoryHelper().getFactory();
+		int operandColumnSpan = operandType.getColumnSpan( sessionFactory );
+		if ( operandColumnSpan > 1 ) {
+			mutateRowValueConstructorSyntax( operandColumnSpan );
+		}
+	}
+
+	protected abstract int getExpansionConnectorType();
+	protected abstract String getExpansionConnectorText();
+
+	private void mutateRowValueConstructorSyntax(int operandColumnSpan) {
+		final int comparisonType = getType();
+		final String comparisonText = getText();
+
+		final int expansionConnectorType = getExpansionConnectorType();
+		final String expansionConnectorText = getExpansionConnectorText();
+
+		setType( expansionConnectorType );
+		setText( expansionConnectorText );
+
+		String[] mutationTexts = extractMutationTexts( getOperand(), operandColumnSpan );
+
+		AST container = this;
+		for ( int i = operandColumnSpan - 1; i > 0; i-- ) {
+			if ( i == 1 ) {
+				AST op1 = getASTFactory().create( comparisonType, comparisonText );
+				AST operand1 = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, mutationTexts[0] );
+				op1.setFirstChild( operand1 );
+				container.setFirstChild( op1 );
+				AST op2 = getASTFactory().create( comparisonType, comparisonText );
+				AST operand2 = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, mutationTexts[1] );
+				op2.setFirstChild( operand2 );
+				op1.setNextSibling( op2 );
+			}
+			else {
+				AST op = getASTFactory().create( comparisonType, comparisonText );
+				AST operand = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, mutationTexts[i] );
+				op.setFirstChild( operand );
+				AST newContainer = getASTFactory().create( expansionConnectorType, expansionConnectorText );
+				container.setFirstChild( newContainer );
+				newContainer.setNextSibling( op );
+				container = newContainer;
+			}
+		}
+	}
+
+	protected Type extractDataType(Node operand) {
+		Type type = null;
+		if ( operand instanceof SqlNode ) {
+			type = ( ( SqlNode ) operand ).getDataType();
+		}
+		if ( type == null && operand instanceof ExpectedTypeAwareNode ) {
+			type = ( ( ExpectedTypeAwareNode ) operand ).getExpectedType();
+		}
+		return type;
+	}
+
+	private 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] = "?";
+			}
+			return rtn;
+		}
+		else if ( operand.getType() == HqlSqlTokenTypes.VECTOR_EXPR ) {
+			String[] rtn = new String[ operand.getNumberOfChildren() ];
+			int x = 0;
+			AST node = operand.getFirstChild();
+			while ( node != null ) {
+				rtn[ x++ ] = node.getText();
+				node = node.getNextSibling();
+			}
+			return rtn;
+		}
+		else if ( operand instanceof SqlNode ) {
+			String nodeText = operand.getText();
+			if ( nodeText.startsWith( "(" ) ) {
+				nodeText = nodeText.substring( 1 );
+			}
+			if ( nodeText.endsWith( ")" ) ) {
+				nodeText = nodeText.substring( 0, nodeText.length() - 1 );
+			}
+			String[] splits = StringHelper.split( ", ", nodeText );
+			if ( count != splits.length ) {
+				throw new HibernateException( "SqlNode's text did not reference expected number of columns" );
+			}
+			return splits;
+		}
+		else {
+			throw new HibernateException( "dont know how to extract row value elements from node : " + operand );
+		}
+	}
+}

Added: core/branches/Branch_3_2/src/org/hibernate/hql/ast/tree/IsNotNullLogicOperatorNode.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/hql/ast/tree/IsNotNullLogicOperatorNode.java	                        (rev 0)
+++ core/branches/Branch_3_2/src/org/hibernate/hql/ast/tree/IsNotNullLogicOperatorNode.java	2007-10-17 20:59:49 UTC (rev 14097)
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
+ *
+ * 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, v. 2.1. This program is distributed in the
+ * hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
+ * distribution; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Red Hat Author(s): Steve Ebersole
+ */
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.hql.antlr.HqlSqlTokenTypes;
+
+/**
+ * IsNotNullLogicOperatorNode implementation
+ *
+ * @author Steve Ebersole
+ */
+public class IsNotNullLogicOperatorNode extends AbstractNullnessCheckNode {
+	protected int getExpansionConnectorType() {
+		return HqlSqlTokenTypes.OR;
+	}
+
+	protected String getExpansionConnectorText() {
+		return "OR";
+	}
+}

Added: core/branches/Branch_3_2/src/org/hibernate/hql/ast/tree/IsNullLogicOperatorNode.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/hql/ast/tree/IsNullLogicOperatorNode.java	                        (rev 0)
+++ core/branches/Branch_3_2/src/org/hibernate/hql/ast/tree/IsNullLogicOperatorNode.java	2007-10-17 20:59:49 UTC (rev 14097)
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
+ *
+ * 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, v. 2.1. This program is distributed in the
+ * hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
+ * distribution; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Red Hat Author(s): Steve Ebersole
+ */
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.hql.antlr.HqlSqlTokenTypes;
+
+/**
+ * Represents a 'is null' check. 
+ *
+ * @author Steve Ebersole
+ */
+public class IsNullLogicOperatorNode extends AbstractNullnessCheckNode {
+	protected int getExpansionConnectorType() {
+		return HqlSqlTokenTypes.AND;
+	}
+
+	protected String getExpansionConnectorText() {
+		return "AND";
+	}
+}

Modified: core/branches/Branch_3_2/src/org/hibernate/hql/ast/tree/UnaryLogicOperatorNode.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/hql/ast/tree/UnaryLogicOperatorNode.java	2007-10-17 20:59:18 UTC (rev 14096)
+++ core/branches/Branch_3_2/src/org/hibernate/hql/ast/tree/UnaryLogicOperatorNode.java	2007-10-17 20:59:49 UTC (rev 14097)
@@ -4,9 +4,11 @@
 import org.hibernate.Hibernate;
 
 /**
- * @author <a href="mailto:steve at hibernate.org">Steve Ebersole </a>
+ * Represents a unary operator node.
+ *
+ * @author Steve Ebersole
  */
-public class UnaryLogicOperatorNode extends SqlNode implements UnaryOperatorNode {
+public class UnaryLogicOperatorNode extends HqlSqlWalkerNode implements UnaryOperatorNode {
 	public Node getOperand() {
 		return ( Node ) getFirstChild();
 	}

Modified: core/branches/Branch_3_2/test/org/hibernate/test/hql/ASTParserLoadingTest.java
===================================================================
--- core/branches/Branch_3_2/test/org/hibernate/test/hql/ASTParserLoadingTest.java	2007-10-17 20:59:18 UTC (rev 14096)
+++ core/branches/Branch_3_2/test/org/hibernate/test/hql/ASTParserLoadingTest.java	2007-10-17 20:59:49 UTC (rev 14097)
@@ -101,6 +101,41 @@
 		return new FunctionalTestClassTestSuite( ASTParserLoadingTest.class );
 	}
 
+	public void testComponentNullnessChecks() {
+		Session s = openSession();
+		s.beginTransaction();
+		Human h = new Human();
+		h.setName( new Name( "Johnny", 'B', "Goode" ) );
+		s.save( h );
+		h = new Human();
+		h.setName( new Name( "Steve", null, "Ebersole" ) );
+		s.save( h );
+		h = new Human();
+		h.setName( new Name( "Bono", null, null ) );
+		s.save( h );
+		h = new Human();
+		h.setName( new Name( null, null, null ) );
+		s.save( h );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		List results = s.createQuery( "from Human where name is null" ).list();
+		assertEquals( 1, results.size() );
+		results = s.createQuery( "from Human where name is not null" ).list();
+		assertEquals( 3, results.size() );
+		s.createQuery( "from Human where ? is null" ).setParameter( 0, null ).list();
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		s.createQuery( "delete Human" ).executeUpdate();
+		s.getTransaction().commit();
+		s.close();
+	}
+
 	public void testInvalidCollectionDereferencesFail() {
 		Session s = openSession();
 		s.beginTransaction();




More information about the hibernate-commits mailing list