[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