From be0c5273b34174aae44350df4503a69bf28a5932 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Thu, 9 Oct 2008 17:23:32 +0000 Subject: [PATCH] HHH-3519 : parameters in select clause git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@15305 1b8cb986-b30d-0410-93ca-fae66ebed9b2 --- .../org/hibernate/dialect/DB2Dialect.java | 22 +++++++++++++-- .../java/org/hibernate/dialect/Dialect.java | 15 ++++++++-- .../org/hibernate/hql/ast/HqlSqlWalker.java | 28 +++++++++++++++++++ .../test/hql/BulkManipulationTest.java | 6 ++-- 4 files changed, 64 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/org/hibernate/dialect/DB2Dialect.java b/core/src/main/java/org/hibernate/dialect/DB2Dialect.java index acdc2bb514..eb9f005ece 100644 --- a/core/src/main/java/org/hibernate/dialect/DB2Dialect.java +++ b/core/src/main/java/org/hibernate/dialect/DB2Dialect.java @@ -374,10 +374,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/core/src/main/java/org/hibernate/dialect/Dialect.java b/core/src/main/java/org/hibernate/dialect/Dialect.java index a84fb895c2..b1c5bbd86a 100644 --- a/core/src/main/java/org/hibernate/dialect/Dialect.java +++ b/core/src/main/java/org/hibernate/dialect/Dialect.java @@ -1617,8 +1617,8 @@ public abstract class Dialect { } /** - * Does this dialect support parameters within the select clause of - * INSERT ... SELECT ... statements? + * Does this dialect support parameters within the SELECT clause of + * INSERT ... SELECT ... statements? * * @return True if this is supported; false otherwise. * @since 3.2 @@ -1627,6 +1627,17 @@ public abstract class Dialect { return true; } + /** + * 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 select clause parameter must be cast()ed + * @since 3.2 + */ + public boolean requiresCastingOfParametersInSelectClause() { + return false; + } + /** * Does this dialect support asking the result set its positioning * information on forward only cursors. Specifically, in the case of diff --git a/core/src/main/java/org/hibernate/hql/ast/HqlSqlWalker.java b/core/src/main/java/org/hibernate/hql/ast/HqlSqlWalker.java index 4457f54954..b89e4c6f16 100644 --- a/core/src/main/java/org/hibernate/hql/ast/HqlSqlWalker.java +++ b/core/src/main/java/org/hibernate/hql/ast/HqlSqlWalker.java @@ -683,10 +683,38 @@ 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 ( isIntegral( versionType ) ) { diff --git a/testsuite/src/test/java/org/hibernate/test/hql/BulkManipulationTest.java b/testsuite/src/test/java/org/hibernate/test/hql/BulkManipulationTest.java index 756d3397b7..b2cd456f66 100644 --- a/testsuite/src/test/java/org/hibernate/test/hql/BulkManipulationTest.java +++ b/testsuite/src/test/java/org/hibernate/test/hql/BulkManipulationTest.java @@ -415,11 +415,13 @@ public class BulkManipulationTest extends FunctionalTestCase { reportSkip( "bulk id generation not supported", "test bulk inserts with generated id and generated timestamp"); return; } + // 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() ) { - reportSkip( "dialect does not support parameter in INSERT ... SELECT", "test bulk inserts with generated id and generated timestamp"); + if ( ! getDialect().supportsParametersInInsertSelect() ) { + reportSkip( "dialect does not support parameter in INSERT ... SELECT", + "test bulk inserts with generated id and generated timestamp"); return; }