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
This commit is contained in:
Manuel Bernhardt 2013-08-20 19:29:17 -04:00 committed by Brett Meyer
parent 51deee1e66
commit 9304c2b3e9
6 changed files with 81 additions and 11 deletions

View File

@ -409,6 +409,7 @@ selectExpr
| collectionFunction // elements() or indices() | collectionFunction // elements() or indices()
| literal | literal
| arithmeticExpr | arithmeticExpr
| parameter
| query | query
; ;

View File

@ -246,7 +246,7 @@ selectExpr
| aggregate | aggregate
| c:constant { out(c); } | c:constant { out(c); }
| arithmeticExpr | arithmeticExpr
| param:PARAM { out(param); } | parameter
| sn:SQL_NODE { out(sn); } | sn:SQL_NODE { out(sn); }
| { out("("); } selectStatement { out(")"); } | { out("("); } selectStatement { out(")"); }
; ;

View File

@ -36,12 +36,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; 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.HibernateException;
import org.hibernate.QueryException; import org.hibernate.QueryException;
import org.hibernate.engine.internal.JoinSequence; import org.hibernate.engine.internal.JoinSequence;
@ -104,6 +98,12 @@ import org.hibernate.type.DbTimestampType;
import org.hibernate.type.Type; import org.hibernate.type.Type;
import org.hibernate.type.VersionType; import org.hibernate.type.VersionType;
import org.hibernate.usertype.UserVersionType; 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). * 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() && final boolean includeVersionProperty = persister.isVersioned() &&
!insertStatement.getIntoClause().isExplicitVersionInsertion() && !insertStatement.getIntoClause().isExplicitVersionInsertion() &&
persister.isVersionPropertyInsertable(); persister.isVersionPropertyInsertable();

View File

@ -116,12 +116,16 @@ public class IntoClause extends HqlSqlWalkerNode implements DisplayableNode {
public void validateTypes(SelectClause selectClause) throws QueryException { public void validateTypes(SelectClause selectClause) throws QueryException {
Type[] selectTypes = selectClause.getQueryReturnTypes(); 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" ); throw new QueryException( "number of select types did not match those for insert" );
} }
int parameterCount = 0;
for ( int i = 0; i < types.length; i++ ) { 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( throw new QueryException(
"insertion type [" + types[i] + "] and selection type [" + "insertion type [" + types[i] + "] and selection type [" +
selectTypes[i] + "] at position " + i + " are not compatible" selectTypes[i] + "] at position " + i + " are not compatible"

View File

@ -24,18 +24,22 @@
*/ */
package org.hibernate.hql.internal.ast.tree; package org.hibernate.hql.internal.ast.tree;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import antlr.collections.AST;
import org.hibernate.hql.internal.antlr.SqlTokenTypes; import org.hibernate.hql.internal.antlr.SqlTokenTypes;
import org.hibernate.hql.internal.ast.util.ASTPrinter; import org.hibernate.hql.internal.ast.util.ASTPrinter;
import antlr.collections.AST;
/** /**
* Common behavior - a node that contains a list of select expressions. * Common behavior - a node that contains a list of select expressions.
* *
* @author josh * @author josh
*/ */
public abstract class SelectExpressionList extends HqlSqlWalkerNode { public abstract class SelectExpressionList extends HqlSqlWalkerNode {
private List<Integer> parameterPositions = new ArrayList<Integer>();
/** /**
* Returns an array of SelectExpressions gathered from the children of the given parent AST node. * 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 firstChild = getFirstSelectExpression();
AST parent = this; AST parent = this;
ArrayList list = new ArrayList( parent.getNumberOfChildren() ); ArrayList list = new ArrayList( parent.getNumberOfChildren() );
int p = 0;
for ( AST n = firstChild; n != null; n = n.getNextSibling() ) { for ( AST n = firstChild; n != null; n = n.getNextSibling() ) {
if ( n instanceof SelectExpression ) { if ( n instanceof SelectExpression ) {
list.add( n ); list.add( n );
} }
else if( n instanceof ParameterNode ) {
parameterPositions.add(p);
}
else { else {
throw new IllegalStateException( "Unexpected AST: " + n.getClass().getName() + " " + new ASTPrinter( SqlTokenTypes.class ).showAsString( n, "" ) ); throw new IllegalStateException( "Unexpected AST: " + n.getClass().getName() + " " + new ASTPrinter( SqlTokenTypes.class ).showAsString( n, "" ) );
} }
p++;
} }
return ( SelectExpression[] ) list.toArray( new SelectExpression[list.size()] ); 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<Integer> getParameterPositions() {
return parameterPositions;
}
/** /**
* Returns the first select expression node that should be considered when building the array of select * Returns the first select expression node that should be considered when building the array of select
* expressions. * expressions.

View File

@ -209,6 +209,30 @@ public class BulkManipulationTest extends BaseCoreFunctionalTestCase {
data.cleanup(); 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 @Test
public void testSimpleNativeSQLInsert() { public void testSimpleNativeSQLInsert() {
TestData data = new TestData(); TestData data = new TestData();