From 9304c2b3e94cb289f6144fcce8982beac9dc392e Mon Sep 17 00:00:00 2001 From: Manuel Bernhardt Date: Tue, 20 Aug 2013 19:29:17 -0400 Subject: [PATCH] Least-effort fix for HHH-2692 Conflicts: hibernate-core/src/main/java/org/hibernate/hql/ast/HqlSqlWalker.java hibernate-core/src/main/java/org/hibernate/hql/ast/tree/IntoClause.java hibernate-core/src/main/java/org/hibernate/hql/ast/tree/SelectExpressionList.java hibernate-core/src/test/java/org/hibernate/test/hql/BulkManipulationTest.java --- hibernate-core/src/main/antlr/hql-sql.g | 1 + hibernate-core/src/main/antlr/sql-gen.g | 2 +- .../hql/internal/ast/HqlSqlWalker.java | 26 ++++++++++++---- .../hql/internal/ast/tree/IntoClause.java | 8 +++-- .../ast/tree/SelectExpressionList.java | 31 +++++++++++++++++-- .../test/hql/BulkManipulationTest.java | 24 ++++++++++++++ 6 files changed, 81 insertions(+), 11 deletions(-) diff --git a/hibernate-core/src/main/antlr/hql-sql.g b/hibernate-core/src/main/antlr/hql-sql.g index fbeb556da7..51437f6a21 100644 --- a/hibernate-core/src/main/antlr/hql-sql.g +++ b/hibernate-core/src/main/antlr/hql-sql.g @@ -409,6 +409,7 @@ selectExpr | collectionFunction // elements() or indices() | literal | arithmeticExpr + | parameter | query ; diff --git a/hibernate-core/src/main/antlr/sql-gen.g b/hibernate-core/src/main/antlr/sql-gen.g index 2bbfec192b..40eeb94d48 100644 --- a/hibernate-core/src/main/antlr/sql-gen.g +++ b/hibernate-core/src/main/antlr/sql-gen.g @@ -246,7 +246,7 @@ selectExpr | aggregate | c:constant { out(c); } | arithmeticExpr - | param:PARAM { out(param); } + | parameter | sn:SQL_NODE { out(sn); } | { out("("); } selectStatement { out(")"); } ; diff --git a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/HqlSqlWalker.java b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/HqlSqlWalker.java index 81d312c93e..a65814abb8 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/HqlSqlWalker.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/HqlSqlWalker.java @@ -36,12 +36,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import antlr.ASTFactory; -import antlr.RecognitionException; -import antlr.SemanticException; -import antlr.collections.AST; -import org.jboss.logging.Logger; - import org.hibernate.HibernateException; import org.hibernate.QueryException; import org.hibernate.engine.internal.JoinSequence; @@ -104,6 +98,12 @@ import org.hibernate.type.DbTimestampType; import org.hibernate.type.Type; import org.hibernate.type.VersionType; import org.hibernate.usertype.UserVersionType; +import org.jboss.logging.Logger; + +import antlr.ASTFactory; +import antlr.RecognitionException; +import antlr.SemanticException; +import antlr.collections.AST; /** * Implements methods used by the HQL->SQL tree transform grammar (a.k.a. the second phase). @@ -775,6 +775,20 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par } } + if ( sessionFactoryHelper.getFactory().getDialect().supportsParametersInInsertSelect() ) { + AST child = selectClause.getFirstChild(); + int i = 0; + while(child != null) { + if(child instanceof ParameterNode) { + // infer the parameter type from the type listed in the INSERT INTO clause + ((ParameterNode)child).setExpectedType(insertStatement.getIntoClause() + .getInsertionTypes()[selectClause.getParameterPositions().get(i)]); + i++; + } + child = child.getNextSibling(); + } + } + final boolean includeVersionProperty = persister.isVersioned() && !insertStatement.getIntoClause().isExplicitVersionInsertion() && persister.isVersionPropertyInsertable(); diff --git a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/IntoClause.java b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/IntoClause.java index 2e3855e94e..88c81f41e1 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/IntoClause.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/IntoClause.java @@ -116,12 +116,16 @@ public class IntoClause extends HqlSqlWalkerNode implements DisplayableNode { public void validateTypes(SelectClause selectClause) throws QueryException { Type[] selectTypes = selectClause.getQueryReturnTypes(); - if ( selectTypes.length != types.length ) { + if ( selectTypes.length + selectClause.getTotalParameterCount() != types.length ) { throw new QueryException( "number of select types did not match those for insert" ); } + int parameterCount = 0; for ( int i = 0; i < types.length; i++ ) { - if ( !areCompatible( types[i], selectTypes[i] ) ) { + if( selectClause.getParameterPositions().contains(i) ) { + parameterCount++; + } + else if ( !areCompatible( types[i], selectTypes[i - parameterCount] ) ) { throw new QueryException( "insertion type [" + types[i] + "] and selection type [" + selectTypes[i] + "] at position " + i + " are not compatible" diff --git a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/SelectExpressionList.java b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/SelectExpressionList.java index 919b243444..4fce4734c9 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/SelectExpressionList.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/SelectExpressionList.java @@ -24,18 +24,22 @@ */ package org.hibernate.hql.internal.ast.tree; import java.util.ArrayList; - -import antlr.collections.AST; +import java.util.List; import org.hibernate.hql.internal.antlr.SqlTokenTypes; import org.hibernate.hql.internal.ast.util.ASTPrinter; +import antlr.collections.AST; + /** * Common behavior - a node that contains a list of select expressions. * * @author josh */ public abstract class SelectExpressionList extends HqlSqlWalkerNode { + + private List parameterPositions = new ArrayList(); + /** * Returns an array of SelectExpressions gathered from the children of the given parent AST node. * @@ -47,17 +51,40 @@ public abstract class SelectExpressionList extends HqlSqlWalkerNode { AST firstChild = getFirstSelectExpression(); AST parent = this; ArrayList list = new ArrayList( parent.getNumberOfChildren() ); + int p = 0; for ( AST n = firstChild; n != null; n = n.getNextSibling() ) { if ( n instanceof SelectExpression ) { list.add( n ); } + else if( n instanceof ParameterNode ) { + parameterPositions.add(p); + } else { throw new IllegalStateException( "Unexpected AST: " + n.getClass().getName() + " " + new ASTPrinter( SqlTokenTypes.class ).showAsString( n, "" ) ); } + p++; } return ( SelectExpression[] ) list.toArray( new SelectExpression[list.size()] ); } + /** + * The total number of parameter projections of this expression. + * + * @return The number of parameters in this select clause. + */ + public int getTotalParameterCount() { + return parameterPositions.size(); + } + + /** + * The position of parameters within the list of select expressions of this clause + * + * @return a list of positions representing the mapping from order of occurence to position + */ + public List getParameterPositions() { + return parameterPositions; + } + /** * Returns the first select expression node that should be considered when building the array of select * expressions. diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/BulkManipulationTest.java b/hibernate-core/src/test/java/org/hibernate/test/hql/BulkManipulationTest.java index a9ed92449e..efbc5de7aa 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/hql/BulkManipulationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/hql/BulkManipulationTest.java @@ -209,6 +209,30 @@ public class BulkManipulationTest extends BaseCoreFunctionalTestCase { data.cleanup(); } + @Test + public void testSimpleInsertWithNamedParam() { + TestData data = new TestData(); + data.prepare(); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + + org.hibernate.Query q = s.createQuery( "insert into Pickup (id, owner, vin) select id, :owner, vin from Car" ); + q.setParameter("owner", "owner"); + + q.executeUpdate(); + + t.commit(); + t = s.beginTransaction(); + + s.createQuery( "delete Vehicle" ).executeUpdate(); + + t.commit(); + s.close(); + + data.cleanup(); + } + @Test public void testSimpleNativeSQLInsert() { TestData data = new TestData();