HHH-2692 Handling subqueries in INSERT...SELECT, disallowing use of

:parameters in SELECT if not in INSERT...SELECT, additional test cases

Conflicts:
	hibernate-core/src/main/java/org/hibernate/hql/ast/tree/SelectClause.java
	hibernate-core/src/test/java/org/hibernate/test/hql/BulkManipulationTest.java
This commit is contained in:
Manuel Bernhardt 2013-08-20 19:33:36 -04:00 committed by Brett Meyer
parent 6ad0d4cfbe
commit f1e4bfbffd
2 changed files with 94 additions and 3 deletions

View File

@ -26,16 +26,17 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import antlr.SemanticException;
import antlr.collections.AST;
import org.hibernate.QueryException;
import org.hibernate.hql.internal.antlr.HqlSqlTokenTypes;
import org.hibernate.hql.internal.antlr.SqlTokenTypes;
import org.hibernate.hql.internal.ast.util.ASTAppender;
import org.hibernate.hql.internal.ast.util.ASTIterator;
import org.hibernate.hql.internal.ast.util.ASTPrinter;
import org.hibernate.type.Type;
import antlr.SemanticException;
import antlr.collections.AST;
/**
* Represents the list of expressions in a SELECT clause.
*
@ -139,6 +140,11 @@ public class SelectClause extends SelectExpressionList {
// changes the AST!!!
SelectExpression[] selectExpressions = collectSelectExpressions();
// we only support parameters in select in the case of INSERT...SELECT statements
if (getParameterPositions().size() > 0 && getWalker().getStatementType() != HqlSqlTokenTypes.INSERT) {
throw new QueryException("Parameters are only supported in SELECT clauses when used as part of a INSERT INTO DML statement");
}
for ( int i = 0; i < selectExpressions.length; i++ ) {
SelectExpression selectExpression = selectExpressions[i];
@ -148,6 +154,17 @@ public class SelectClause extends SelectExpressionList {
scalarSelect = true;
}
else {
// we have no choice but to do this check here
// this is not very elegant but the "right way" would most likely involve a bigger rewrite so as to
// treat ParameterNodes in select clauses as SelectExpressions
boolean inSubquery = selectExpression instanceof QueryNode && ((QueryNode) selectExpression).getFromClause().getParentFromClause() != null;
if (getWalker().getStatementType() == HqlSqlTokenTypes.INSERT && inSubquery) {
// we do not support parameters for subqueries in INSERT...SELECT
if (((QueryNode) selectExpression).getSelectClause().getParameterPositions().size() > 0) {
throw new QueryException("Use of parameters in subqueries of INSERT INTO DML statements is not supported.");
}
}
Type type = selectExpression.getDataType();
if ( type == null ) {
throw new IllegalStateException( "No data type for node: " + selectExpression.getClass().getName() + " "

View File

@ -209,6 +209,19 @@ public class BulkManipulationTest extends BaseCoreFunctionalTestCase {
data.cleanup();
}
@Test
public void testSelectWithNamedParamProjection() {
Session s = openSession();
try {
s.createQuery("select :someParameter, id from Car");
fail("Should throw an unsupported exception");
} catch(QueryException q) {
// allright
} finally {
s.close();
}
}
@Test
public void testSimpleInsertWithNamedParam() {
TestData data = new TestData();
@ -233,6 +246,67 @@ public class BulkManipulationTest extends BaseCoreFunctionalTestCase {
data.cleanup();
}
@Test
public void testInsertWithMultipleNamedParams() {
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("id", 5l);
q.setParameter("vin", "some");
q.executeUpdate();
t.commit();
t = s.beginTransaction();
s.createQuery( "delete Vehicle" ).executeUpdate();
t.commit();
s.close();
data.cleanup();
}
@Test
public void testInsertWithSubqueriesAndNamedParams() {
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, (select a.description from Animal a where a.description = :description), :vin from Car" );
q.setParameter("id", 5l);
q.setParameter("description", "Frog");
q.setParameter("vin", "some");
q.executeUpdate();
t.commit();
t = s.beginTransaction();
try {
org.hibernate.Query q1 = s.createQuery( "insert into Pickup (id, owner, vin) select :id, (select :description from Animal a where a.description = :description), :vin from Car" );
fail("Unsupported exception should have been thrown");
} catch(QueryException e) {
assertTrue(e.getMessage().indexOf("Use of parameters in subqueries of INSERT INTO DML statements is not supported.") > -1);
}
t = s.beginTransaction();
s.createQuery( "delete Vehicle" ).executeUpdate();
t.commit();
s.close();
data.cleanup();
}
@Test
public void testSimpleInsertTypeMismatchException() {