From a008b898d6d102a955217b05d78bec78e1162a75 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Wed, 8 Oct 2008 22:59:59 +0000 Subject: [PATCH] HHH-3519 : params in select clause git-svn-id: https://svn.jboss.org/repos/hibernate/core/branches/Branch_3_2@15293 1b8cb986-b30d-0410-93ca-fae66ebed9b2 --- src/org/hibernate/dialect/DB2Dialect.java | 22 ++++++- src/org/hibernate/dialect/Dialect.java | 10 ++-- src/org/hibernate/hql/ast/HqlSqlWalker.java | 57 +++++++++---------- .../test/hql/BulkManipulationTest.java | 3 +- 4 files changed, 53 insertions(+), 39 deletions(-) diff --git a/src/org/hibernate/dialect/DB2Dialect.java b/src/org/hibernate/dialect/DB2Dialect.java index e590f4ed8b..e72808d900 100644 --- a/src/org/hibernate/dialect/DB2Dialect.java +++ b/src/org/hibernate/dialect/DB2Dialect.java @@ -351,10 +351,26 @@ public class DB2Dialect extends Dialect { return false; } + /** + * {@inheritDoc} + *

+ * DB2 is know to support parameters in the SELECT clause, but only in casted form + * (see {@link #requiresCastingOfParametersInSelectClause()}). + * + * @return True. + */ public boolean supportsParametersInInsertSelect() { - // DB2 known to not support parameters within the select - // clause of an SQL INSERT ... SELECT ... statement - return false; + return true; + } + + /** + * DB2 in fact does require that parameters appearing in the select clause be wrapped in cast() calls + * to tell the DB parser the type of the select value. + * + * @return True. + */ + public boolean requiresCastingOfParametersInSelectClause() { + return true; } public boolean supportsResultSetPositionQueryMethodsOnForwardOnlyCursor() { diff --git a/src/org/hibernate/dialect/Dialect.java b/src/org/hibernate/dialect/Dialect.java index b04ebf2937..7d45536d1d 100644 --- a/src/org/hibernate/dialect/Dialect.java +++ b/src/org/hibernate/dialect/Dialect.java @@ -1595,14 +1595,14 @@ public abstract class Dialect { } /** - * Does this dialect support casted parameters within the select clause of - * INSERT ... SELECT ... cast( ? as ) statements? + * Does this dialect require that parameters appearing in the SELECT clause be wrapped in cast() + * calls to tell the db parser the expected type. * - * @return True if this is supported; false otherwise. + * @return True if select clause parameter must be cast()ed * @since 3.2 */ - public boolean supportsCastedParametersInInsertSelect() { - return true; + public boolean requiresCastingOfParametersInSelectClause() { + return false; } /** diff --git a/src/org/hibernate/hql/ast/HqlSqlWalker.java b/src/org/hibernate/hql/ast/HqlSqlWalker.java index 2f290e7971..afb112893c 100644 --- a/src/org/hibernate/hql/ast/HqlSqlWalker.java +++ b/src/org/hibernate/hql/ast/HqlSqlWalker.java @@ -15,7 +15,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.QueryException; import org.hibernate.HibernateException; -import org.hibernate.AssertionFailure; import org.hibernate.engine.JoinSequence; import org.hibernate.engine.ParameterBinder; import org.hibernate.engine.SessionFactoryImplementor; @@ -662,39 +661,39 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par AST versionValueNode = null; if ( sessionFactoryHelper.getFactory().getDialect().supportsParametersInInsertSelect() ) { + int sqlTypes[] = versionType.sqlTypes( sessionFactoryHelper.getFactory() ); + if ( sqlTypes == null || sqlTypes.length == 0 ) { + throw new IllegalStateException( versionType.getClass() + ".sqlTypes() returns null or empty array" ); + } + if ( sqlTypes.length > 1 ) { + throw new IllegalStateException( + versionType.getClass() + + ".sqlTypes() returns > 1 element; only single-valued versions are allowed." + ); + } versionValueNode = getASTFactory().create( HqlSqlTokenTypes.PARAM, "?" ); ParameterSpecification paramSpec = new VersionTypeSeedParameterSpecification( versionType ); ( ( ParameterNode ) versionValueNode ).setHqlParameterSpecification( paramSpec ); parameters.add( 0, paramSpec ); + + if ( sessionFactoryHelper.getFactory().getDialect().requiresCastingOfParametersInSelectClause() ) { + // we need to wrtap the param in a cast() + MethodNode versionMethodNode = ( MethodNode ) getASTFactory().create( HqlSqlTokenTypes.METHOD_CALL, "(" ); + AST methodIdentNode = getASTFactory().create( HqlSqlTokenTypes.IDENT, "cast" ); + versionMethodNode.addChild( methodIdentNode ); + versionMethodNode.initializeMethodNode(methodIdentNode, true ); + AST castExprListNode = getASTFactory().create( HqlSqlTokenTypes.EXPR_LIST, "exprList" ); + methodIdentNode.setNextSibling( castExprListNode ); + castExprListNode.addChild( versionValueNode ); + versionValueNode.setNextSibling( + getASTFactory().create( + HqlSqlTokenTypes.IDENT, + sessionFactoryHelper.getFactory().getDialect().getTypeName( sqlTypes[0] ) ) + ); + processFunction( versionMethodNode, true ); + versionValueNode = versionMethodNode; + } } - else if ( sessionFactoryHelper.getFactory().getDialect().supportsCastedParametersInInsertSelect() ) { - int sqlTypes[] = versionType.sqlTypes( sessionFactoryHelper.getFactory() ); - if ( sqlTypes == null || sqlTypes.length == 0 ) { - throw new AssertionFailure( versionType.getClass() + "sqlTypes() returns null or empty array" ); - } - if ( sqlTypes.length > 1 ) { - throw new UnsupportedOperationException( versionType.getClass() + - ".sqlTypes() returns > 1 element; only single-valued versions are allowed." ); - } - MethodNode versionMethodNode = ( MethodNode ) getASTFactory().create( HqlSqlTokenTypes.METHOD_CALL, "(" ); - AST methodIdentNode = getASTFactory().create( HqlSqlTokenTypes.IDENT, "cast" ); - versionMethodNode.initializeMethodNode(methodIdentNode, true ); - versionMethodNode.addChild( methodIdentNode ); - AST castExprListNode = getASTFactory().create( HqlSqlTokenTypes.EXPR_LIST, "exprList" ); - methodIdentNode.setNextSibling( castExprListNode ); - AST paramNode = getASTFactory().create( HqlSqlTokenTypes.PARAM, "?" ); - ParameterSpecification paramSpec = new VersionTypeSeedParameterSpecification( versionType ); - ( ( ParameterNode ) paramNode ).setHqlParameterSpecification( paramSpec ); - castExprListNode.addChild( paramNode ); - paramNode.setNextSibling( - getASTFactory().create( - HqlSqlTokenTypes.IDENT, - sessionFactoryHelper.getFactory().getDialect().getTypeName( sqlTypes[0] ) ) - ); - processFunction( versionMethodNode, true ); - versionValueNode = versionMethodNode; - parameters.add( 0, paramSpec ); - } else { if ( isIntegral( versionType ) ) { try { diff --git a/test/org/hibernate/test/hql/BulkManipulationTest.java b/test/org/hibernate/test/hql/BulkManipulationTest.java index 3b61b0624d..0882578c7c 100644 --- a/test/org/hibernate/test/hql/BulkManipulationTest.java +++ b/test/org/hibernate/test/hql/BulkManipulationTest.java @@ -419,8 +419,7 @@ public class BulkManipulationTest extends FunctionalTestCase { // dialects which do not allow a parameter in the select portion of an INSERT ... SELECT statement // will also be problematic for this test because the timestamp here is vm-based as opposed to // db-based. - if ( !getDialect().supportsParametersInInsertSelect() && - !getDialect().supportsCastedParametersInInsertSelect() ) { + if ( ! getDialect().supportsParametersInInsertSelect() ) { reportSkip( "dialect does not support parameter in INSERT ... SELECT", "test bulk inserts with generated id and generated timestamp"); return;