Author: ste...@jb...
Date: 2006-06-27 22:53:39 -0400 (Tue, 27 Jun 2006)
New Revision: 10060
Added:
trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BooleanLiteralNode.java
trunk/Hibernate3/test/org/hibernate/test/hql/BooleanLiteralEntity.hbm.xml
trunk/Hibernate3/test/org/hibernate/test/hql/BooleanLiteralEntity.java
Modified:
trunk/Hibernate3/src/org/hibernate/dialect/Dialect.java
trunk/Hibernate3/src/org/hibernate/dialect/MySQLDialect.java
trunk/Hibernate3/src/org/hibernate/dialect/PostgreSQLDialect.java
trunk/Hibernate3/src/org/hibernate/hql/ast/HqlSqlWalker.java
trunk/Hibernate3/src/org/hibernate/hql/ast/SqlASTFactory.java
trunk/Hibernate3/src/org/hibernate/hql/ast/SqlGenerator.java
trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BinaryLogicOperatorNode.java
trunk/Hibernate3/src/org/hibernate/hql/ast/tree/FromElementType.java
trunk/Hibernate3/src/org/hibernate/hql/ast/tree/JavaConstantNode.java
trunk/Hibernate3/src/org/hibernate/hql/ast/tree/LiteralNode.java
trunk/Hibernate3/src/org/hibernate/hql/ast/tree/Node.java
trunk/Hibernate3/src/org/hibernate/hql/ast/tree/ParameterNode.java
trunk/Hibernate3/src/org/hibernate/impl/AbstractQueryImpl.java
trunk/Hibernate3/test/org/hibernate/test/component/ComponentTest.java
trunk/Hibernate3/test/org/hibernate/test/component/User.hbm.xml
trunk/Hibernate3/test/org/hibernate/test/hql/ASTParserLoadingTest.java
trunk/Hibernate3/test/org/hibernate/test/hql/BulkManipulationTest.java
trunk/Hibernate3/test/org/hibernate/test/hql/FooBarCopy.hbm.xml
trunk/Hibernate3/test/org/hibernate/test/hql/HQLTest.java
trunk/Hibernate3/test/org/hibernate/test/hql/QueryTranslatorTestCase.java
Log:
HHH-1855 : HQL and boolean handling (literals and params);
HHH-1858 : HQL and many-to-any;
HHH-1861 : HQL and components
Modified: trunk/Hibernate3/src/org/hibernate/dialect/Dialect.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/dialect/Dialect.java 2006-06-28 02:37:56 UTC (rev 10059)
+++ trunk/Hibernate3/src/org/hibernate/dialect/Dialect.java 2006-06-28 02:53:39 UTC (rev 10060)
@@ -1060,4 +1060,20 @@
public LockingStrategy getLockingStrategy(Lockable lockable, LockMode lockMode) {
return new SelectLockingStrategy( lockable, lockMode );
}
+
+ /**
+ * Is this dialect known to support what ANSI-SQL terms "row value
+ * constructor" syntax; sometimes called tuple syntax.
+ * <p/>
+ * Basically, does it support syntax like
+ * "... where (FIRST_NAME, LAST_NAME) = ('Steve', 'Ebersole') ...".
+ *
+ * @return True if this SQL dialect is known to support "row value
+ * constructor" syntax; false otherwise.
+ * @since 3.2
+ */
+ public boolean supportsRowValueConstructorSyntax() {
+ // return false here, as most databases do not properly support this construct...
+ return false;
+ }
}
Modified: trunk/Hibernate3/src/org/hibernate/dialect/MySQLDialect.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/dialect/MySQLDialect.java 2006-06-28 02:37:56 UTC (rev 10059)
+++ trunk/Hibernate3/src/org/hibernate/dialect/MySQLDialect.java 2006-06-28 02:53:39 UTC (rev 10060)
@@ -320,5 +320,8 @@
ResultSet rs = ps.getResultSet();
return rs;
}
-
+
+ public boolean supportsRowValueConstructorSyntax() {
+ return true;
+ }
}
\ No newline at end of file
Modified: trunk/Hibernate3/src/org/hibernate/dialect/PostgreSQLDialect.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/dialect/PostgreSQLDialect.java 2006-06-28 02:37:56 UTC (rev 10059)
+++ trunk/Hibernate3/src/org/hibernate/dialect/PostgreSQLDialect.java 2006-06-28 02:53:39 UTC (rev 10060)
@@ -293,4 +293,7 @@
}
};
+ public boolean supportsRowValueConstructorSyntax() {
+ return true;
+ }
}
Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/HqlSqlWalker.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/hql/ast/HqlSqlWalker.java 2006-06-28 02:37:56 UTC (rev 10059)
+++ trunk/Hibernate3/src/org/hibernate/hql/ast/HqlSqlWalker.java 2006-06-28 02:53:39 UTC (rev 10060)
@@ -45,8 +45,6 @@
import org.hibernate.hql.ast.tree.UpdateStatement;
import org.hibernate.hql.ast.tree.Node;
import org.hibernate.hql.ast.tree.OperatorNode;
-import org.hibernate.hql.ast.tree.BinaryLogicOperatorNode;
-import org.hibernate.hql.ast.tree.InLogicOperatorNode;
import org.hibernate.hql.ast.util.ASTPrinter;
import org.hibernate.hql.ast.util.ASTUtil;
import org.hibernate.hql.ast.util.AliasGenerator;
@@ -923,6 +921,7 @@
}
protected void evaluateAssignment(AST eq) throws SemanticException {
+ prepareLogicOperator( eq );
Queryable persister = getCurrentFromClause().getFromElement().getQueryable();
evaluateAssignment( eq, persister, -1 );
}
Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/SqlASTFactory.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/hql/ast/SqlASTFactory.java 2006-06-28 02:37:56 UTC (rev 10059)
+++ trunk/Hibernate3/src/org/hibernate/hql/ast/SqlASTFactory.java 2006-06-28 02:53:39 UTC (rev 10060)
@@ -39,6 +39,7 @@
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;
@@ -117,9 +118,10 @@
case NUM_LONG:
case NUM_DOUBLE:
case QUOTED_STRING:
+ return LiteralNode.class;
case TRUE:
case FALSE:
- return LiteralNode.class;
+ return BooleanLiteralNode.class;
case JAVA_CONSTANT:
return JavaConstantNode.class;
case ORDER:
Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/SqlGenerator.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/hql/ast/SqlGenerator.java 2006-06-28 02:37:56 UTC (rev 10059)
+++ trunk/Hibernate3/src/org/hibernate/hql/ast/SqlGenerator.java 2006-06-28 02:53:39 UTC (rev 10060)
@@ -13,13 +13,14 @@
import org.hibernate.hql.antlr.SqlGeneratorBase;
import org.hibernate.hql.ast.tree.MethodNode;
import org.hibernate.hql.ast.tree.FromElement;
-import org.hibernate.hql.ast.tree.JavaConstantNode;
+import org.hibernate.hql.ast.tree.Node;
/**
* Generates SQL by overriding callback methods in the base class, which does
* the actual SQL AST walking.
*
- * @author Joshua
+ * @author Joshua Davis
+ * @author Steve Ebersole
*/
public class SqlGenerator extends SqlGeneratorBase implements ErrorReporter {
/**
@@ -45,8 +46,8 @@
}
protected void out(AST n) {
- if ( n instanceof JavaConstantNode ) {
- out( ( ( JavaConstantNode ) n ).getSqlText() );
+ if ( n instanceof Node ) {
+ out( ( ( Node ) n ).getRenderText( sessionFactory ) );
}
else {
super.out( n );
Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BinaryLogicOperatorNode.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BinaryLogicOperatorNode.java 2006-06-28 02:37:56 UTC (rev 10059)
+++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BinaryLogicOperatorNode.java 2006-06-28 02:53:39 UTC (rev 10060)
@@ -2,14 +2,21 @@
import org.hibernate.type.Type;
import org.hibernate.Hibernate;
+import org.hibernate.TypeMismatchException;
+import org.hibernate.HibernateException;
+import org.hibernate.util.StringHelper;
+import org.hibernate.hql.antlr.HqlSqlTokenTypes;
+import org.hibernate.dialect.HSQLDialect;
+import org.hibernate.engine.SessionFactoryImplementor;
import antlr.SemanticException;
+import antlr.collections.AST;
/**
* Contract for nodes representing binary operators.
*
* @author Steve Ebersole
*/
-public class BinaryLogicOperatorNode extends SqlNode implements BinaryOperatorNode {
+public class BinaryLogicOperatorNode extends HqlSqlWalkerNode implements BinaryOperatorNode {
/**
* Performs the operator node initialization by seeking out any parameter
* nodes and setting their expected type, if possible.
@@ -23,16 +30,149 @@
if ( rhs == null ) {
throw new SemanticException( "right-hand operand of a binary operator was null" );
}
- if ( ExpectedTypeAwareNode.class.isAssignableFrom( lhs.getClass() )
- && SqlNode.class.isAssignableFrom( rhs.getClass() ) ) {
- ( ( ExpectedTypeAwareNode ) lhs ).setExpectedType( ( ( SqlNode ) rhs ).getDataType() );
+
+ Type lhsType = extractDataType( lhs );
+ Type rhsType = extractDataType( rhs );
+
+ if ( lhsType == null ) {
+ lhsType = rhsType;
}
- else if ( ExpectedTypeAwareNode.class.isAssignableFrom( rhs.getClass() )
- && SqlNode.class.isAssignableFrom( lhs.getClass() ) ) {
- ( ( ExpectedTypeAwareNode ) rhs ).setExpectedType( ( ( SqlNode ) lhs ).getDataType() );
+ if ( rhsType == null ) {
+ rhsType = lhsType;
}
+
+ if ( ExpectedTypeAwareNode.class.isAssignableFrom( lhs.getClass() ) ) {
+ ( ( ExpectedTypeAwareNode ) lhs ).setExpectedType( rhsType );
+ }
+ if ( ExpectedTypeAwareNode.class.isAssignableFrom( rhs.getClass() ) ) {
+ ( ( ExpectedTypeAwareNode ) rhs ).setExpectedType( lhsType );
+ }
+
+ mutateRowValueConstructorSyntaxesIfNecessary( lhsType, rhsType );
}
+ protected final void mutateRowValueConstructorSyntaxesIfNecessary(Type lhsType, Type rhsType) {
+ // TODO : this really needs to be delayed unitl after we definitively know all node types
+ // where this is currently a problem is parameters for which where we cannot unequivocally
+ // resolve an expected type
+ SessionFactoryImplementor sessionFactory = getSessionFactoryHelper().getFactory();
+ if ( lhsType != null && rhsType != null ) {
+ int lhsColumnSpan = lhsType.getColumnSpan( sessionFactory );
+ if ( lhsColumnSpan != rhsType.getColumnSpan( sessionFactory ) ) {
+ throw new TypeMismatchException(
+ "left and right hand sides of a binary logic operator were incompatibile [" +
+ lhsType.getName() + " : "+ rhsType.getName() + "]"
+ );
+ }
+ if ( lhsColumnSpan > 1 ) {
+ // for dialects which are known to not support ANSI-SQL row-value-constructor syntax,
+ // we should mutate the tree.
+ if ( !sessionFactory.getDialect().supportsRowValueConstructorSyntax() ) {
+ mutateRowValueConstructorSyntax( lhsColumnSpan );
+ }
+ }
+ }
+ }
+
+ /**
+ * Mutate the subtree relating to a row-value-constructor to instead use
+ * a series of ANDed predicates. This allows multi-column type comparisons
+ * and explicit row-value-constructor syntax even on databases which do
+ * not support row-value-constructor.
+ * <p/>
+ * For example, here we'd mutate "... where (col1, col2) = ('val1', 'val2) ..." to
+ * "... where col1 = 'val1' and col2 = 'val2' ..."
+ *
+ * @param valueElements The number of elements in the row value constructor list.
+ */
+ private void mutateRowValueConstructorSyntax(int valueElements) {
+ // mutation depends on the types of nodes invloved...
+ int comparisonType = getType();
+ String comparisonText = getText();
+ setType( HqlSqlTokenTypes.AND );
+ setText( "AND" );
+ String[] lhsElementTexts = extractMutationTexts( getLeftHandOperand(), valueElements );
+ String[] rhsElementTexts = extractMutationTexts( getRightHandOperand(), valueElements );
+
+ AST container = this;
+ for ( int i = valueElements - 1; i > 0; i-- ) {
+
+ if ( i == 1 ) {
+ AST op1 = getASTFactory().create( comparisonType, comparisonText );
+ AST lhs1 = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, lhsElementTexts[0] );
+ AST rhs1 = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, rhsElementTexts[0] );
+ op1.setFirstChild( lhs1 );
+ lhs1.setNextSibling( rhs1 );
+ container.setFirstChild( op1 );
+ AST op2 = getASTFactory().create( comparisonType, comparisonText );
+ AST lhs2 = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, lhsElementTexts[1] );
+ AST rhs2 = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, rhsElementTexts[1] );
+ op2.setFirstChild( lhs2 );
+ lhs2.setNextSibling( rhs2 );
+ op1.setNextSibling( op2 );
+ }
+ else {
+ AST op = getASTFactory().create( comparisonType, comparisonText );
+ AST lhs = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, lhsElementTexts[i] );
+ AST rhs = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, rhsElementTexts[i] );
+ op.setFirstChild( lhs );
+ lhs.setNextSibling( rhs );
+ AST newContainer = getASTFactory().create( HqlSqlTokenTypes.AND, "AND" );
+ container.setFirstChild( newContainer );
+ newContainer.setNextSibling( op );
+ container = newContainer;
+ }
+ }
+ }
+
+ 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 );
+ }
+ }
+
+ 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;
+ }
+
public Type getDataType() {
// logic operators by definition resolve to booleans
return Hibernate.BOOLEAN;
Added: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BooleanLiteralNode.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BooleanLiteralNode.java 2006-06-28 02:37:56 UTC (rev 10059)
+++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BooleanLiteralNode.java 2006-06-28 02:53:39 UTC (rev 10060)
@@ -0,0 +1,50 @@
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.type.Type;
+import org.hibernate.type.BooleanType;
+import org.hibernate.Hibernate;
+import org.hibernate.QueryException;
+import org.hibernate.engine.SessionFactoryImplementor;
+
+/**
+ * Represents a boolean literal within a query.
+ *
+ * @author Steve Ebersole
+ */
+public class BooleanLiteralNode extends LiteralNode implements ExpectedTypeAwareNode {
+ private Type expectedType;
+
+ public Type getDataType() {
+ return expectedType == null ? Hibernate.BOOLEAN : expectedType;
+ }
+
+ public BooleanType getTypeInternal() {
+ return ( BooleanType ) getDataType();
+ }
+
+ public Boolean getValue() {
+ return getType() == TRUE ? Boolean.TRUE : Boolean.FALSE;
+ }
+
+ /**
+ * Expected-types really only pertinent here for boolean literals...
+ *
+ * @param expectedType
+ */
+ public void setExpectedType(Type expectedType) {
+ this.expectedType = expectedType;
+ }
+
+ public Type getExpectedType() {
+ return expectedType;
+ }
+
+ public String getRenderText(SessionFactoryImplementor sessionFactory) {
+ try {
+ return getTypeInternal().objectToSQLString( getValue(), sessionFactory.getDialect() );
+ }
+ catch( Throwable t ) {
+ throw new QueryException( "Unable to render boolean literal value", t );
+ }
+ }
+}
Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/FromElementType.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/FromElementType.java 2006-06-28 02:37:56 UTC (rev 10059)
+++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/FromElementType.java 2006-06-28 02:53:39 UTC (rev 10060)
@@ -381,7 +381,14 @@
}
return collectionPropertyMapping;
}
- if ( queryableCollection.getElementType().isComponentType() ) { // Collection of components.
+ if ( queryableCollection.getElementType().isAnyType() ) {
+ // collection of <many-to-any/> mappings...
+ // used to circumvent the component-collection check below...
+ return queryableCollection;
+
+ }
+ if ( queryableCollection.getElementType().isComponentType() ) {
+ // Collection of components.
if ( propertyName.equals( EntityPersister.ENTITY_ID ) ) {
return ( PropertyMapping ) queryableCollection.getOwnerEntityPersister();
}
Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/JavaConstantNode.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/JavaConstantNode.java 2006-06-28 02:37:56 UTC (rev 10059)
+++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/JavaConstantNode.java 2006-06-28 02:53:39 UTC (rev 10060)
@@ -48,11 +48,6 @@
this.factory = factory;
}
- public String getSqlText() {
- Type type = expectedType == null ? heuristicType : expectedType;
- return resolveToLiteralString( type );
- }
-
private String resolveToLiteralString(Type type) {
try {
LiteralType literalType = ( LiteralType ) type;
@@ -63,4 +58,9 @@
throw new QueryException( QueryTranslator.ERROR_CANNOT_FORMAT_LITERAL + constantExpression, t );
}
}
+
+ public String getRenderText(SessionFactoryImplementor sessionFactory) {
+ Type type = expectedType == null ? heuristicType : expectedType;
+ return resolveToLiteralString( type );
+ }
}
Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/LiteralNode.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/LiteralNode.java 2006-06-28 02:37:56 UTC (rev 10059)
+++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/LiteralNode.java 2006-06-28 02:53:39 UTC (rev 10060)
@@ -38,5 +38,4 @@
return null;
}
}
-
}
Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/Node.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/Node.java 2006-06-28 02:37:56 UTC (rev 10059)
+++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/Node.java 2006-06-28 02:53:39 UTC (rev 10060)
@@ -3,12 +3,13 @@
import antlr.collections.AST;
import antlr.Token;
import org.hibernate.util.StringHelper;
+import org.hibernate.engine.SessionFactoryImplementor;
/**
- * Generic AST Node.
- * User: Joshua Davis<br>
- * Date: Sep 23, 2005<br>
- * Time: 12:20:53 PM<br>
+ * Base node class for use by Hibernate within its AST trees.
+ *
+ * @author Joshua Davis
+ * @author Steve Ebersole
*/
public class Node extends antlr.CommonAST {
private String filename;
@@ -24,6 +25,17 @@
super(tok); // This will call initialize(tok)!
}
+ /**
+ * Retrieve the text to be used for rendering this particular node.
+ *
+ * @param sessionFactory The session factory
+ * @return The text to use for rendering
+ */
+ public String getRenderText(SessionFactoryImplementor sessionFactory) {
+ // The basic implementation is to simply use the node's text
+ return getText();
+ }
+
public void initialize(Token tok) {
super.initialize(tok);
filename = tok.getFilename();
@@ -34,9 +46,8 @@
}
public void initialize(AST t) {
- super.initialize(t);
- if (t instanceof Node)
- {
+ super.initialize( t );
+ if ( t instanceof Node ) {
Node n = (Node)t;
filename = n.filename;
line = n.line;
Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/ParameterNode.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/ParameterNode.java 2006-06-28 02:37:56 UTC (rev 10059)
+++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/ParameterNode.java 2006-06-28 02:53:39 UTC (rev 10060)
@@ -3,6 +3,7 @@
import org.hibernate.param.ParameterSpecification;
import org.hibernate.type.Type;
+import org.hibernate.engine.SessionFactoryImplementor;
/**
* Implementation of ParameterNode.
@@ -32,4 +33,20 @@
public Type getExpectedType() {
return getHqlParameterSpecification() == null ? null : getHqlParameterSpecification().getExpectedType();
}
+
+ public String getRenderText(SessionFactoryImplementor sessionFactory) {
+ int count = 0;
+ if ( getExpectedType() != null && ( count = getExpectedType().getColumnSpan( sessionFactory ) ) > 1 ) {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append( "(?" );
+ for ( int i = 1; i < count; i++ ) {
+ buffer.append( ", ?" );
+ }
+ buffer.append( ")" );
+ return buffer.toString();
+ }
+ else {
+ return "?";
+ }
+ }
}
Modified: trunk/Hibernate3/src/org/hibernate/impl/AbstractQueryImpl.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/impl/AbstractQueryImpl.java 2006-06-28 02:37:56 UTC (rev 10059)
+++ trunk/Hibernate3/src/org/hibernate/impl/AbstractQueryImpl.java 2006-06-28 02:53:39 UTC (rev 10060)
@@ -385,6 +385,14 @@
return this;
}
+ protected Type determineType(int paramPosition, Object paramValue, Type defaultType) {
+ Type type = parameterMetadata.getOrdinalParameterExpectedType( paramPosition + 1 );
+ if ( type == null ) {
+ type = defaultType;
+ }
+ return type;
+ }
+
protected Type determineType(int paramPosition, Object paramValue) throws HibernateException {
Type type = parameterMetadata.getOrdinalParameterExpectedType( paramPosition + 1 );
if ( type == null ) {
@@ -393,6 +401,14 @@
return type;
}
+ protected Type determineType(String paramName, Object paramValue, Type defaultType) {
+ Type type = parameterMetadata.getNamedParameterExpectedType( paramName );
+ if ( type == null ) {
+ type = defaultType;
+ }
+ return type;
+ }
+
protected Type determineType(String paramName, Object paramValue) throws HibernateException {
Type type = parameterMetadata.getNamedParameterExpectedType( paramName );
if ( type == null ) {
@@ -448,7 +464,9 @@
}
public Query setBoolean(int position, boolean val) {
- setParameter(position, val ? Boolean.TRUE : Boolean.FALSE, Hibernate.BOOLEAN);
+ Boolean valueToUse = val ? Boolean.TRUE : Boolean.FALSE;
+ Type typeToUse = determineType( position, valueToUse, Hibernate.BOOLEAN );
+ setParameter( position, valueToUse, typeToUse );
return this;
}
@@ -543,7 +561,9 @@
}
public Query setBoolean(String name, boolean val) {
- setParameter(name, val ? Boolean.TRUE : Boolean.FALSE, Hibernate.BOOLEAN);
+ Boolean valueToUse = val ? Boolean.TRUE : Boolean.FALSE;
+ Type typeToUse = determineType( name, valueToUse, Hibernate.BOOLEAN );
+ setParameter( name, valueToUse, typeToUse );
return this;
}
Modified: trunk/Hibernate3/test/org/hibernate/test/component/ComponentTest.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/component/ComponentTest.java 2006-06-28 02:37:56 UTC (rev 10059)
+++ trunk/Hibernate3/test/org/hibernate/test/component/ComponentTest.java 2006-06-28 02:53:39 UTC (rev 10060)
@@ -14,6 +14,7 @@
import org.hibernate.dialect.HSQLDialect;
import org.hibernate.dialect.Oracle9Dialect;
import org.hibernate.dialect.PostgreSQLDialect;
+import org.hibernate.dialect.SQLServerDialect;
import org.hibernate.test.TestCase;
/**
@@ -89,6 +90,28 @@
t.commit();
s.close();
}
+
+ public void testComponentQueries() {
+// if ( !dialectSupportsRowValueConstructorSyntax() ) {
+// return;
+// }
+ Session s = openSession();
+ Transaction t = s.beginTransaction();
+ Employee emp = new Employee();
+ emp.setHireDate( new Date() );
+ emp.setPerson( new Person() );
+ emp.getPerson().setName( "steve" );
+ emp.getPerson().setDob( new Date() );
+ s.save( emp );
+
+ s.createQuery( "from Employee e where e.person = :p and 1 = 1 and 2=2" ).setParameter( "p", emp.getPerson() ).list();
+ s.createQuery( "from Employee e where :p = e.person" ).setParameter( "p", emp.getPerson() ).list();
+ s.createQuery( "from Employee e where e.person = ('steve', current_timestamp)" ).list();
+
+ s.delete( emp );
+ t.commit();
+ s.close();
+ }
public void testComponentFormulaQuery() {
@@ -110,7 +133,7 @@
t.commit();
s.close();
}
-
+
public void testNamedQuery() {
if ( getDialect() instanceof PostgreSQLDialect ) return; //postgres got no year() function
if ( getDialect() instanceof Oracle9Dialect ) return; //oracle got no year() function
Modified: trunk/Hibernate3/test/org/hibernate/test/component/User.hbm.xml
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/component/User.hbm.xml 2006-06-28 02:37:56 UTC (rev 10059)
+++ trunk/Hibernate3/test/org/hibernate/test/component/User.hbm.xml 2006-06-28 02:53:39 UTC (rev 10060)
@@ -25,6 +25,17 @@
update="false"/>
</component>
</class>
+
+ <class name="Employee" table="T_EMP">
+ <id name="id" type="long" column="ID">
+ <generator class="increment"/>
+ </id>
+ <property name="hireDate" type="date" column="HIRE_DATE"/>
+ <component name="person">
+ <property name="name" update="false" not-null="true"/>
+ <property name="dob" update="false" not-null="true"/>
+ </component>
+ </class>
<query name="userNameIn"><![CDATA[from User where person.name in (:nameList) or userName in (:nameList)]]></query>
Modified: trunk/Hibernate3/test/org/hibernate/test/hql/ASTParserLoadingTest.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/hql/ASTParserLoadingTest.java 2006-06-28 02:37:56 UTC (rev 10059)
+++ trunk/Hibernate3/test/org/hibernate/test/hql/ASTParserLoadingTest.java 2006-06-28 02:53:39 UTC (rev 10060)
@@ -31,6 +31,12 @@
import org.hibernate.dialect.Oracle9Dialect;
import org.hibernate.stat.QueryStatistics;
import org.hibernate.test.TestCase;
+import org.hibernate.test.any.PropertyValue;
+import org.hibernate.test.any.StringPropertyValue;
+import org.hibernate.test.any.IntegerPropertyValue;
+import org.hibernate.test.any.PropertySet;
+import org.hibernate.test.legacy.Bar;
+import org.hibernate.test.legacy.One;
import org.hibernate.test.cid.Customer;
import org.hibernate.test.cid.LineItem;
import org.hibernate.test.cid.Order;
@@ -68,14 +74,15 @@
protected String[] getMappings() {
// Make sure we are using the new AST parser translator...
System.setProperty( Environment.QUERY_TRANSLATOR, "org.hibernate.hql.ast.ASTQueryTranslatorFactory" );
- return new String[]{
- "hql/Animal.hbm.xml",
- "hql/FooBarCopy.hbm.xml",
- "batchfetch/ProductLine.hbm.xml",
- "cid/Customer.hbm.xml",
- "cid/Order.hbm.xml",
- "cid/LineItem.hbm.xml",
- "cid/Product.hbm.xml"
+ return new String[] {
+ "hql/Animal.hbm.xml",
+ "hql/FooBarCopy.hbm.xml",
+ "batchfetch/ProductLine.hbm.xml",
+ "cid/Customer.hbm.xml",
+ "cid/Order.hbm.xml",
+ "cid/LineItem.hbm.xml",
+ "cid/Product.hbm.xml",
+ "any/Properties.hbm.xml"
};
}
@@ -86,6 +93,62 @@
}
+ public void testComponentQueries() {
+ Session s = openSession();
+ s.beginTransaction();
+
+ // Test the ability to perform comparisions between component values
+ s.createQuery( "from Human h where h.name = h.name" ).list();
+ s.createQuery( "from Human h where h.name = :name" ).setParameter( "name", new Name() ).list();
+ s.createQuery( "from Human where name = :name" ).setParameter( "name", new Name() ).list();
+ s.createQuery( "from Human h where :name = h.name" ).setParameter( "name", new Name() ).list();
+ s.createQuery( "from Human h where :name <> h.name" ).setParameter( "name", new Name() ).list();
+
+ // Test the ability to perform comparisions between a component and an explicit row-value
+ s.createQuery( "from Human h where h.name = ('John', 'X', 'Doe')" ).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();
+
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ public void testAnyMappingReference() {
+ Session s = openSession();
+ s.beginTransaction();
+
+ PropertyValue redValue = new StringPropertyValue( "red" );
+ PropertyValue lonliestNumberValue = new IntegerPropertyValue( 1 );
+
+ Long id;
+ PropertySet ps = new PropertySet( "my properties" );
+ ps.setSomeSpecificProperty( redValue );
+ ps.getGeneralProperties().put( "the lonliest number", lonliestNumberValue );
+ ps.getGeneralProperties().put( "i like", new StringPropertyValue( "pina coladas" ) );
+ ps.getGeneralProperties().put( "i also like", new StringPropertyValue( "getting caught in the rain" ) );
+ s.save( ps );
+
+ s.getTransaction().commit();
+ id = ps.getId();
+ s.clear();
+ s.beginTransaction();
+
+ // TODO : setEntity() currently will not work here, but that would be *very* nice
+ // does not work because the corresponding EntityType is then used as the "bind type" rather
+ // than the "discovered" AnyType...
+ s.createQuery( "from PropertySet p where p.someSpecificProperty = :ssp" ).setParameter( "ssp", redValue ).list();
+
+ s.createQuery( "from PropertySet p where p.someSpecificProperty.id is not null" ).list();
+
+ s.createQuery( "from PropertySet p join p.generalProperties gp where gp.id is not null" ).list();
+
+ s.delete( s.load( PropertySet.class, id ) );
+
+ s.getTransaction().commit();
+ s.close();
+ }
+
public void testJdkEnumStyleEnumConstant() throws Exception {
Session s = openSession();
s.beginTransaction();
Added: trunk/Hibernate3/test/org/hibernate/test/hql/BooleanLiteralEntity.hbm.xml
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/hql/BooleanLiteralEntity.hbm.xml 2006-06-28 02:37:56 UTC (rev 10059)
+++ trunk/Hibernate3/test/org/hibernate/test/hql/BooleanLiteralEntity.hbm.xml 2006-06-28 02:53:39 UTC (rev 10060)
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.test.hql" default-access="field">
+
+ <class name="BooleanLiteralEntity">
+ <id name="id">
+ <generator class="native"/>
+ </id>
+ <property name="yesNoBoolean" column="Y_N_BOOL" type="yes_no"/>
+ <property name="trueFalseBoolean" column="T_F_BOOL" type="true_false"/>
+ <property name="zeroOneBoolean" column="NUM_BOOL" type="boolean"/>
+ </class>
+
+</hibernate-mapping>
\ No newline at end of file
Added: trunk/Hibernate3/test/org/hibernate/test/hql/BooleanLiteralEntity.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/hql/BooleanLiteralEntity.java 2006-06-28 02:37:56 UTC (rev 10059)
+++ trunk/Hibernate3/test/org/hibernate/test/hql/BooleanLiteralEntity.java 2006-06-28 02:53:39 UTC (rev 10060)
@@ -0,0 +1,45 @@
+package org.hibernate.test.hql;
+
+/**
+ * todo: describe BooleanLiteralEntity
+ *
+ * @author Steve Ebersole
+ */
+public class BooleanLiteralEntity {
+ private Long id;
+ private boolean yesNoBoolean;
+ private boolean trueFalseBoolean;
+ private boolean zeroOneBoolean;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public boolean isYesNoBoolean() {
+ return yesNoBoolean;
+ }
+
+ public void setYesNoBoolean(boolean yesNoBoolean) {
+ this.yesNoBoolean = yesNoBoolean;
+ }
+
+ public boolean isTrueFalseBoolean() {
+ return trueFalseBoolean;
+ }
+
+ public void setTrueFalseBoolean(boolean trueFalseBoolean) {
+ this.trueFalseBoolean = trueFalseBoolean;
+ }
+
+ public boolean isZeroOneBoolean() {
+ return zeroOneBoolean;
+ }
+
+ public void setZeroOneBoolean(boolean zeroOneBoolean) {
+ this.zeroOneBoolean = zeroOneBoolean;
+ }
+}
Modified: trunk/Hibernate3/test/org/hibernate/test/hql/BulkManipulationTest.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/hql/BulkManipulationTest.java 2006-06-28 02:37:56 UTC (rev 10059)
+++ trunk/Hibernate3/test/org/hibernate/test/hql/BulkManipulationTest.java 2006-06-28 02:53:39 UTC (rev 10060)
@@ -43,7 +43,8 @@
"hql/FooBarCopy.hbm.xml",
"legacy/Multi.hbm.xml",
"hql/EntityWithCrazyCompositeKey.hbm.xml",
- "hql/SimpleEntityWithAssociation.hbm.xml"
+ "hql/SimpleEntityWithAssociation.hbm.xml",
+ "hql/BooleanLiteralEntity.hbm.xml"
};
}
@@ -112,6 +113,43 @@
}
+ // BOOLEAN HANDLING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ public void testBooleanHandling() {
+ TestData data = new TestData();
+ data.prepare();
+
+ Session s = openSession();
+ Transaction t = s.beginTransaction();
+
+ // currently, we need the three different binds because they are different underlying types...
+ int count = s.createQuery( "update BooleanLiteralEntity set yesNoBoolean = :b1, trueFalseBoolean = :b2, zeroOneBoolean = :b3" )
+ .setBoolean( "b1", true )
+ .setBoolean( "b2", true )
+ .setBoolean( "b3", true )
+ .executeUpdate();
+ assertEquals( 1, count );
+ BooleanLiteralEntity entity = ( BooleanLiteralEntity ) s.createQuery( "from BooleanLiteralEntity" ).uniqueResult();
+ assertTrue( entity.isYesNoBoolean() );
+ assertTrue( entity.isTrueFalseBoolean() );
+ assertTrue( entity.isZeroOneBoolean() );
+ s.clear();
+
+ count = s.createQuery( "update BooleanLiteralEntity set yesNoBoolean = true, trueFalseBoolean = true, zeroOneBoolean = true" )
+ .executeUpdate();
+ assertEquals( 1, count );
+ entity = ( BooleanLiteralEntity ) s.createQuery( "from BooleanLiteralEntity" ).uniqueResult();
+ assertTrue( entity.isYesNoBoolean() );
+ assertTrue( entity.isTrueFalseBoolean() );
+ assertTrue( entity.isZeroOneBoolean() );
+
+ t.commit();
+ s.close();
+
+ data.cleanup();
+ }
+
+
// INSERTS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public void testSimpleInsert() {
@@ -411,6 +449,14 @@
// UPDATES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ public void testIncorrectSyntax() {
+ Session s = openSession();
+ Transaction t = s.beginTransaction();
+ s.createQuery( "update Human set Human.description = 'xyz' where Human.id = 1 and Human.description is null" ).executeUpdate();
+ t.commit();
+ s.close();
+ }
+
public void testUpdateWithWhereExistsSubquery() {
// multi-table ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Session s = openSession();
@@ -1130,6 +1176,9 @@
pickup.setOwner( "Cecelia" );
s.save( pickup );
+ BooleanLiteralEntity bool = new BooleanLiteralEntity();
+ s.save( bool );
+
txn.commit();
s.close();
}
@@ -1144,6 +1193,7 @@
s.createQuery( "delete from Zoo" ).executeUpdate();
s.createQuery( "delete from Joiner" ).executeUpdate();
s.createQuery( "delete from Vehicle" ).executeUpdate();
+ s.createQuery( "delete from BooleanLiteralEntity" ).executeUpdate();
txn.commit();
s.close();
Modified: trunk/Hibernate3/test/org/hibernate/test/hql/FooBarCopy.hbm.xml
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/hql/FooBarCopy.hbm.xml 2006-06-28 02:37:56 UTC (rev 10059)
+++ trunk/Hibernate3/test/org/hibernate/test/hql/FooBarCopy.hbm.xml 2006-06-28 02:53:39 UTC (rev 10060)
@@ -118,6 +118,20 @@
</subclass>
</class>
+ <class name="One" table="one">
+ <id name="key" column="one_key">
+ <generator class="native" />
+ </id>
+ <property name="x"/>
+ <property column="one_value" name="value"/>
+ </class>
+ <class name="Many" table="many">
+ <id name="key" column="many_key">
+ <generator class="native" />
+ </id>
+ <property name="x"/>
+ </class>
+
</hibernate-mapping>
Modified: trunk/Hibernate3/test/org/hibernate/test/hql/HQLTest.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/hql/HQLTest.java 2006-06-28 02:37:56 UTC (rev 10059)
+++ trunk/Hibernate3/test/org/hibernate/test/hql/HQLTest.java 2006-06-28 02:53:39 UTC (rev 10060)
@@ -54,6 +54,11 @@
//FAILING TESTS:
+ public void testManyToAnyReferences() {
+ assertTranslation( "from PropertySet p where p.someSpecificProperty.id is not null" );
+ assertTranslation( "from PropertySet p join p.generalProperties gp where gp.id is not null" );
+ }
+
public void testJoinFetchCollectionOfValues() {
assertTranslation( "select h from Human as h join fetch h.nickNames" );
}
Modified: trunk/Hibernate3/test/org/hibernate/test/hql/QueryTranslatorTestCase.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/hql/QueryTranslatorTestCase.java 2006-06-28 02:37:56 UTC (rev 10059)
+++ trunk/Hibernate3/test/org/hibernate/test/hql/QueryTranslatorTestCase.java 2006-06-28 02:53:39 UTC (rev 10060)
@@ -495,40 +495,41 @@
}
protected String[] getMappings() {
- return new String[]{
- "hql/Animal.hbm.xml",
- "hql/EntityWithCrazyCompositeKey.hbm.xml",
- "batchfetch/ProductLine.hbm.xml",
- "cid/Customer.hbm.xml",
- "cid/Order.hbm.xml",
- "cid/LineItem.hbm.xml",
- "cid/Product.hbm.xml",
- "legacy/Baz.hbm.xml",
- "legacy/Category.hbm.xml",
- "legacy/Commento.hbm.xml",
- "legacy/Container.hbm.xml",
- "legacy/Custom.hbm.xml",
- "legacy/Eye.hbm.xml",
- "legacy/Fee.hbm.xml",
- "legacy/FooBar.hbm.xml",
- "legacy/Fum.hbm.xml",
- "legacy/Glarch.hbm.xml",
- "legacy/Holder.hbm.xml",
- "legacy/Many.hbm.xml",
- "legacy/Marelo.hbm.xml",
- "legacy/MasterDetail.hbm.xml",
- "legacy/Middle.hbm.xml",
- "legacy/Multi.hbm.xml",
- "legacy/Nameable.hbm.xml",
- "legacy/One.hbm.xml",
- "legacy/Qux.hbm.xml",
- "legacy/Simple.hbm.xml",
- "legacy/SingleSeveral.hbm.xml",
- "legacy/WZ.hbm.xml",
- "legacy/UpDown.hbm.xml",
- "compositeelement/Parent.hbm.xml",
- "onetoone/joined/Person.hbm.xml",
- "hql/CrazyIdFieldNames.hbm.xml"
+ return new String[] {
+ "hql/Animal.hbm.xml",
+ "hql/EntityWithCrazyCompositeKey.hbm.xml",
+ "batchfetch/ProductLine.hbm.xml",
+ "cid/Customer.hbm.xml",
+ "cid/Order.hbm.xml",
+ "cid/LineItem.hbm.xml",
+ "cid/Product.hbm.xml",
+ "legacy/Baz.hbm.xml",
+ "legacy/Category.hbm.xml",
+ "legacy/Commento.hbm.xml",
+ "legacy/Container.hbm.xml",
+ "legacy/Custom.hbm.xml",
+ "legacy/Eye.hbm.xml",
+ "legacy/Fee.hbm.xml",
+ "legacy/FooBar.hbm.xml",
+ "legacy/Fum.hbm.xml",
+ "legacy/Glarch.hbm.xml",
+ "legacy/Holder.hbm.xml",
+ "legacy/Many.hbm.xml",
+ "legacy/Marelo.hbm.xml",
+ "legacy/MasterDetail.hbm.xml",
+ "legacy/Middle.hbm.xml",
+ "legacy/Multi.hbm.xml",
+ "legacy/Nameable.hbm.xml",
+ "legacy/One.hbm.xml",
+ "legacy/Qux.hbm.xml",
+ "legacy/Simple.hbm.xml",
+ "legacy/SingleSeveral.hbm.xml",
+ "legacy/WZ.hbm.xml",
+ "legacy/UpDown.hbm.xml",
+ "compositeelement/Parent.hbm.xml",
+ "onetoone/joined/Person.hbm.xml",
+ "hql/CrazyIdFieldNames.hbm.xml",
+ "any/Properties.hbm.xml"
};
}
|