HHH-11028 - {h-schema} is not replaced in SQLDelete, SQLInsert and SQLUpdate code enhancement
This commit is contained in:
parent
1cb10729b0
commit
090d18dcc8
|
@ -60,6 +60,10 @@ public class SQLQueryParser {
|
||||||
return aliasesFound>0;
|
return aliasesFound>0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected String getOriginalQueryString() {
|
||||||
|
return originalQueryString;
|
||||||
|
}
|
||||||
|
|
||||||
public String process() {
|
public String process() {
|
||||||
String processedSql = substituteBrackets( originalQueryString );
|
String processedSql = substituteBrackets( originalQueryString );
|
||||||
processedSql = substituteParams( processedSql );
|
processedSql = substituteParams( processedSql );
|
||||||
|
@ -68,7 +72,7 @@ public class SQLQueryParser {
|
||||||
|
|
||||||
// TODO: should "record" how many properties we have reffered to - and if we
|
// TODO: should "record" how many properties we have reffered to - and if we
|
||||||
// don't get'em'all we throw an exception! Way better than trial and error ;)
|
// don't get'em'all we throw an exception! Way better than trial and error ;)
|
||||||
private String substituteBrackets(String sqlQuery) throws QueryException {
|
protected String substituteBrackets(String sqlQuery) throws QueryException {
|
||||||
|
|
||||||
StringBuilder result = new StringBuilder( sqlQuery.length() + 20 );
|
StringBuilder result = new StringBuilder( sqlQuery.length() + 20 );
|
||||||
int left, right;
|
int left, right;
|
||||||
|
@ -126,7 +130,7 @@ public class SQLQueryParser {
|
||||||
throw new QueryException( "Unknown placeholder ", aliasPath );
|
throw new QueryException( "Unknown placeholder ", aliasPath );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else if (context != null) {
|
||||||
int firstDot = aliasPath.indexOf( '.' );
|
int firstDot = aliasPath.indexOf( '.' );
|
||||||
if ( firstDot == -1 ) {
|
if ( firstDot == -1 ) {
|
||||||
if ( context.isEntityAlias( aliasPath ) ) {
|
if ( context.isEntityAlias( aliasPath ) ) {
|
||||||
|
|
|
@ -70,7 +70,6 @@ import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||||
import org.hibernate.engine.spi.Mapping;
|
import org.hibernate.engine.spi.Mapping;
|
||||||
import org.hibernate.engine.spi.PersistenceContext.NaturalIdHelper;
|
import org.hibernate.engine.spi.PersistenceContext.NaturalIdHelper;
|
||||||
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||||
import org.hibernate.engine.spi.SelfDirtinessTracker;
|
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.engine.spi.ValueInclusion;
|
import org.hibernate.engine.spi.ValueInclusion;
|
||||||
|
@ -87,6 +86,7 @@ import org.hibernate.internal.util.collections.ArrayHelper;
|
||||||
import org.hibernate.jdbc.Expectation;
|
import org.hibernate.jdbc.Expectation;
|
||||||
import org.hibernate.jdbc.Expectations;
|
import org.hibernate.jdbc.Expectations;
|
||||||
import org.hibernate.jdbc.TooManyRowsAffectedException;
|
import org.hibernate.jdbc.TooManyRowsAffectedException;
|
||||||
|
import org.hibernate.loader.custom.sql.SQLQueryParser;
|
||||||
import org.hibernate.loader.entity.BatchingEntityLoaderBuilder;
|
import org.hibernate.loader.entity.BatchingEntityLoaderBuilder;
|
||||||
import org.hibernate.loader.entity.CascadeEntityLoader;
|
import org.hibernate.loader.entity.CascadeEntityLoader;
|
||||||
import org.hibernate.loader.entity.DynamicBatchingEntityLoaderBuilder;
|
import org.hibernate.loader.entity.DynamicBatchingEntityLoaderBuilder;
|
||||||
|
@ -3927,16 +3927,16 @@ public abstract class AbstractEntityPersister
|
||||||
for ( int j = 0; j < joinSpan; j++ ) {
|
for ( int j = 0; j < joinSpan; j++ ) {
|
||||||
sqlInsertStrings[j] = customSQLInsert[j] == null ?
|
sqlInsertStrings[j] = customSQLInsert[j] == null ?
|
||||||
generateInsertString( getPropertyInsertability(), j ) :
|
generateInsertString( getPropertyInsertability(), j ) :
|
||||||
customSQLInsert[j];
|
substituteBrackets( customSQLInsert[j]);
|
||||||
sqlUpdateStrings[j] = customSQLUpdate[j] == null ?
|
sqlUpdateStrings[j] = customSQLUpdate[j] == null ?
|
||||||
generateUpdateString( getPropertyUpdateability(), j, false ) :
|
generateUpdateString( getPropertyUpdateability(), j, false ) :
|
||||||
customSQLUpdate[j];
|
substituteBrackets( customSQLUpdate[j]);
|
||||||
sqlLazyUpdateStrings[j] = customSQLUpdate[j] == null ?
|
sqlLazyUpdateStrings[j] = customSQLUpdate[j] == null ?
|
||||||
generateUpdateString( getNonLazyPropertyUpdateability(), j, false ) :
|
generateUpdateString( getNonLazyPropertyUpdateability(), j, false ) :
|
||||||
customSQLUpdate[j];
|
substituteBrackets( customSQLUpdate[j]);
|
||||||
sqlDeleteStrings[j] = customSQLDelete[j] == null ?
|
sqlDeleteStrings[j] = customSQLDelete[j] == null ?
|
||||||
generateDeleteString( j ) :
|
generateDeleteString( j ) :
|
||||||
customSQLDelete[j];
|
substituteBrackets( customSQLDelete[j]);
|
||||||
}
|
}
|
||||||
|
|
||||||
tableHasColumns = new boolean[joinSpan];
|
tableHasColumns = new boolean[joinSpan];
|
||||||
|
@ -3959,7 +3959,7 @@ public abstract class AbstractEntityPersister
|
||||||
.getInsertGeneratedIdentifierDelegate( this, getFactory().getDialect(), useGetGeneratedKeys() );
|
.getInsertGeneratedIdentifierDelegate( this, getFactory().getDialect(), useGetGeneratedKeys() );
|
||||||
sqlIdentityInsertString = customSQLInsert[0] == null
|
sqlIdentityInsertString = customSQLInsert[0] == null
|
||||||
? generateIdentityInsertString( getPropertyInsertability() )
|
? generateIdentityInsertString( getPropertyInsertability() )
|
||||||
: customSQLInsert[0];
|
: substituteBrackets( customSQLInsert[0] );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sqlIdentityInsertString = null;
|
sqlIdentityInsertString = null;
|
||||||
|
@ -3968,6 +3968,10 @@ public abstract class AbstractEntityPersister
|
||||||
logStaticSQL();
|
logStaticSQL();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String substituteBrackets(String sql) {
|
||||||
|
return new SubstituteBracketSQLQueryParser( sql, getFactory() ).process();
|
||||||
|
}
|
||||||
|
|
||||||
public final void postInstantiate() throws MappingException {
|
public final void postInstantiate() throws MappingException {
|
||||||
doLateInit();
|
doLateInit();
|
||||||
|
|
||||||
|
@ -5559,5 +5563,15 @@ public abstract class AbstractEntityPersister
|
||||||
// };
|
// };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class SubstituteBracketSQLQueryParser extends SQLQueryParser {
|
||||||
|
|
||||||
|
SubstituteBracketSQLQueryParser(String queryString, SessionFactoryImplementor factory) {
|
||||||
|
super( queryString, null, factory );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String process() {
|
||||||
|
return substituteBrackets( getOriginalQueryString() );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.persister.entity;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.Loader;
|
||||||
|
import org.hibernate.annotations.NamedNativeQuery;
|
||||||
|
import org.hibernate.annotations.Persister;
|
||||||
|
import org.hibernate.annotations.ResultCheckStyle;
|
||||||
|
import org.hibernate.annotations.SQLDelete;
|
||||||
|
import org.hibernate.annotations.SQLInsert;
|
||||||
|
import org.hibernate.annotations.SQLUpdate;
|
||||||
|
import org.hibernate.dialect.H2Dialect;
|
||||||
|
|
||||||
|
import org.hibernate.testing.RequiresDialect;
|
||||||
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Laabidi RAISSI
|
||||||
|
*/
|
||||||
|
@RequiresDialect(H2Dialect.class)
|
||||||
|
public class CustomSqlSchemaResolvingIdentityTest extends BaseCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[]{
|
||||||
|
CustomEntity.class, Dummy.class
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSchemaNotReplacedInCustomSQL() throws Exception {
|
||||||
|
|
||||||
|
String className = CustomEntity.class.getName();
|
||||||
|
|
||||||
|
final AbstractEntityPersister persister = (AbstractEntityPersister) sessionFactory().getEntityPersister( className );
|
||||||
|
String insertQuery = persister.getSQLInsertStrings()[0];
|
||||||
|
String updateQuery = persister.getSQLUpdateStrings()[0];
|
||||||
|
String deleteQuery = persister.getSQLDeleteStrings()[0];
|
||||||
|
|
||||||
|
assertEquals( "Incorrect custom SQL for insert in Entity: " + className,
|
||||||
|
"INSERT INTO FOO (name) VALUES (?)", insertQuery );
|
||||||
|
|
||||||
|
assertEquals( "Incorrect custom SQL for delete in Entity: " + className,
|
||||||
|
"DELETE FROM FOO WHERE id = ?", deleteQuery );
|
||||||
|
|
||||||
|
assertEquals( "Incorrect custom SQL for update in Entity: " + className,
|
||||||
|
"UPDATE FOO SET name = ? WHERE id = ? ", updateQuery );
|
||||||
|
|
||||||
|
CustomEntity _entitty = doInHibernate( this::sessionFactory, session -> {
|
||||||
|
CustomEntity entity = new CustomEntity();
|
||||||
|
session.persist( entity );
|
||||||
|
|
||||||
|
return entity;
|
||||||
|
} );
|
||||||
|
|
||||||
|
doInHibernate( this::sessionFactory, session -> {
|
||||||
|
CustomEntity entity = session.find( CustomEntity.class, 1 );
|
||||||
|
assertNotNull(entity);
|
||||||
|
|
||||||
|
entity.name = "Vlad";
|
||||||
|
} );
|
||||||
|
|
||||||
|
doInHibernate( this::sessionFactory, session -> {
|
||||||
|
CustomEntity entity = session.find( CustomEntity.class, _entitty.id );
|
||||||
|
session.delete( entity );
|
||||||
|
} );
|
||||||
|
|
||||||
|
doInHibernate( this::sessionFactory, session -> {
|
||||||
|
CustomEntity entity = session.find( CustomEntity.class, _entitty.id );
|
||||||
|
assertNull(entity);
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "CardWithCustomSQL")
|
||||||
|
@Persister( impl = SingleTableEntityPersister.class )
|
||||||
|
@Loader(namedQuery = "find_foo_by_id")
|
||||||
|
@NamedNativeQuery(
|
||||||
|
name = "find_foo_by_id",
|
||||||
|
query = "SELECT id, name FROM {h-schema}FOO WHERE id = ?",
|
||||||
|
resultClass = CustomEntity.class
|
||||||
|
)
|
||||||
|
@SQLInsert(sql = "INSERT INTO {h-schema}FOO (name) VALUES (?)", callable = true)
|
||||||
|
@SQLDelete(sql = "DELETE FROM {h-schema}FOO WHERE id = ?", check = ResultCheckStyle.COUNT)
|
||||||
|
@SQLUpdate(sql = "UPDATE {h-schema}FOO SET name = ? WHERE id = ? ")
|
||||||
|
public static class CustomEntity {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
public Integer id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Dummy")
|
||||||
|
@Table(name = "FOO")
|
||||||
|
public static class Dummy {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
public Integer id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.persister.entity;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.Loader;
|
||||||
|
import org.hibernate.annotations.NamedNativeQuery;
|
||||||
|
import org.hibernate.annotations.Persister;
|
||||||
|
import org.hibernate.annotations.ResultCheckStyle;
|
||||||
|
import org.hibernate.annotations.SQLDelete;
|
||||||
|
import org.hibernate.annotations.SQLInsert;
|
||||||
|
import org.hibernate.annotations.SQLUpdate;
|
||||||
|
|
||||||
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Laabidi RAISSI
|
||||||
|
*/
|
||||||
|
public class CustomSqlSchemaResolvingTest extends BaseCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[]{
|
||||||
|
CustomEntity.class, Dummy.class
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSchemaNotReplacedInCustomSQL() throws Exception {
|
||||||
|
|
||||||
|
String className = CustomEntity.class.getName();
|
||||||
|
|
||||||
|
final AbstractEntityPersister persister = (AbstractEntityPersister) sessionFactory().getEntityPersister( className );
|
||||||
|
String insertQuery = persister.getSQLInsertStrings()[0];
|
||||||
|
String updateQuery = persister.getSQLUpdateStrings()[0];
|
||||||
|
String deleteQuery = persister.getSQLDeleteStrings()[0];
|
||||||
|
|
||||||
|
assertEquals( "Incorrect custom SQL for insert in Entity: " + className,
|
||||||
|
"INSERT INTO FOO (name, id) VALUES (?, ?)", insertQuery );
|
||||||
|
|
||||||
|
assertEquals( "Incorrect custom SQL for delete in Entity: " + className,
|
||||||
|
"DELETE FROM FOO WHERE id = ?", deleteQuery );
|
||||||
|
|
||||||
|
assertEquals( "Incorrect custom SQL for update in Entity: " + className,
|
||||||
|
"UPDATE FOO SET name = ? WHERE id = ? ", updateQuery );
|
||||||
|
|
||||||
|
doInHibernate( this::sessionFactory, session -> {
|
||||||
|
CustomEntity entity = new CustomEntity();
|
||||||
|
entity.id = 1;
|
||||||
|
session.persist( entity );
|
||||||
|
} );
|
||||||
|
|
||||||
|
doInHibernate( this::sessionFactory, session -> {
|
||||||
|
CustomEntity entity = session.find( CustomEntity.class, 1 );
|
||||||
|
assertNotNull(entity);
|
||||||
|
|
||||||
|
entity.name = "Vlad";
|
||||||
|
} );
|
||||||
|
|
||||||
|
doInHibernate( this::sessionFactory, session -> {
|
||||||
|
CustomEntity entity = session.find( CustomEntity.class, 1 );
|
||||||
|
session.delete( entity );
|
||||||
|
} );
|
||||||
|
|
||||||
|
doInHibernate( this::sessionFactory, session -> {
|
||||||
|
CustomEntity entity = session.find( CustomEntity.class, 1 );
|
||||||
|
assertNull(entity);
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "CardWithCustomSQL")
|
||||||
|
@Persister( impl = SingleTableEntityPersister.class )
|
||||||
|
@Loader(namedQuery = "find_foo_by_id")
|
||||||
|
@NamedNativeQuery(
|
||||||
|
name = "find_foo_by_id",
|
||||||
|
query = "SELECT id, name FROM {h-schema}FOO WHERE id = ?",
|
||||||
|
resultClass = CustomEntity.class
|
||||||
|
)
|
||||||
|
@SQLInsert(sql = "INSERT INTO {h-schema}FOO (name, id) VALUES (?, ?)", callable = true)
|
||||||
|
@SQLDelete(sql = "DELETE FROM {h-schema}FOO WHERE id = ?", check = ResultCheckStyle.COUNT)
|
||||||
|
@SQLUpdate(sql = "UPDATE {h-schema}FOO SET name = ? WHERE id = ? ")
|
||||||
|
public static class CustomEntity {
|
||||||
|
@Id
|
||||||
|
public Integer id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Dummy")
|
||||||
|
@Table(name = "FOO")
|
||||||
|
public static class Dummy {
|
||||||
|
@Id
|
||||||
|
public Integer id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue