diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java index 66c1a9c3ade2..ef18c7ac66ed 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java @@ -24,6 +24,7 @@ import java.util.Map; import java.util.Properties; import java.util.Set; +import java.util.regex.Pattern; import org.hibernate.HibernateException; import org.hibernate.LockMode; @@ -140,6 +141,9 @@ public abstract class Dialect implements ConversionContext { */ public static final String CLOSED_QUOTE = "`\"]"; + private static final Pattern ESCAPE_CLOSING_COMMENT_PATTERN = Pattern.compile( "\\*/" ); + private static final Pattern ESCAPE_OPENING_COMMENT_PATTERN = Pattern.compile( "/\\*" ); + private final TypeNames typeNames = new TypeNames(); private final TypeNames hibernateTypeNames = new TypeNames(); @@ -3002,6 +3006,14 @@ public String addSqlHintOrComment( } protected String prependComment(String sql, String comment) { - return "/* " + comment + " */ " + sql; + return "/* " + escapeComment( comment ) + " */ " + sql; + } + + public static String escapeComment(String comment) { + if ( StringHelper.isNotEmpty( comment ) ) { + final String escaped = ESCAPE_CLOSING_COMMENT_PATTERN.matcher( comment ).replaceAll( "*\\\\/" ); + return ESCAPE_OPENING_COMMENT_PATTERN.matcher( escaped ).replaceAll( "/\\\\*" ); + } + return comment; } } diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/query/internal/SelectStatementBuilder.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/query/internal/SelectStatementBuilder.java index 3d2b1d8ac303..0a1f4df0ec7f 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/query/internal/SelectStatementBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/query/internal/SelectStatementBuilder.java @@ -187,7 +187,7 @@ public String toStatementString() { StringBuilder buf = new StringBuilder( guesstimatedBufferSize ); if ( StringHelper.isNotEmpty( comment ) ) { - buf.append( "/* " ).append( comment ).append( " */ " ); + buf.append( "/* " ).append( Dialect.escapeComment( comment ) ).append( " */ " ); } buf.append( "select " ) diff --git a/hibernate-core/src/main/java/org/hibernate/sql/Delete.java b/hibernate-core/src/main/java/org/hibernate/sql/Delete.java index a6badc03051b..876dd5f76a5f 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/Delete.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/Delete.java @@ -9,6 +9,8 @@ import java.util.LinkedHashMap; import java.util.Map; +import org.hibernate.dialect.Dialect; + /** * An SQL DELETE statement * @@ -36,7 +38,7 @@ public Delete setTableName(String tableName) { public String toStatementString() { StringBuilder buf = new StringBuilder( tableName.length() + 10 ); if ( comment!=null ) { - buf.append( "/* " ).append(comment).append( " */ " ); + buf.append( "/* " ).append( Dialect.escapeComment( comment ) ).append( " */ " ); } buf.append( "delete from " ).append(tableName); if ( where != null || !primaryKeyColumns.isEmpty() || versionColumnName != null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/sql/Insert.java b/hibernate-core/src/main/java/org/hibernate/sql/Insert.java index 49d828c92d9b..ed15af80f8bc 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/Insert.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/Insert.java @@ -90,7 +90,7 @@ public Insert setTableName(String tableName) { public String toStatementString() { StringBuilder buf = new StringBuilder( columns.size()*15 + tableName.length() + 10 ); if ( comment != null ) { - buf.append( "/* " ).append( comment ).append( " */ " ); + buf.append( "/* " ).append( Dialect.escapeComment( comment ) ).append( " */ " ); } buf.append("insert into ") .append(tableName); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/InsertSelect.java b/hibernate-core/src/main/java/org/hibernate/sql/InsertSelect.java index 387ee1d558c5..c9110ec34c60 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/InsertSelect.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/InsertSelect.java @@ -65,7 +65,7 @@ public String toStatementString() { StringBuilder buf = new StringBuilder( (columnNames.size() * 15) + tableName.length() + 10 ); if ( comment!=null ) { - buf.append( "/* " ).append( comment ).append( " */ " ); + buf.append( "/* " ).append( Dialect.escapeComment( comment ) ).append( " */ " ); } buf.append( "insert into " ).append( tableName ); if ( !columnNames.isEmpty() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/sql/QuerySelect.java b/hibernate-core/src/main/java/org/hibernate/sql/QuerySelect.java index 649d97359407..fc685182d8a2 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/QuerySelect.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/QuerySelect.java @@ -126,7 +126,7 @@ public void addOrderBy(String orderByString) { public String toQueryString() { StringBuilder buf = new StringBuilder( 50 ); if ( comment != null ) { - buf.append( "/* " ).append( comment ).append( " */ " ); + buf.append( "/* " ).append( Dialect.escapeComment( comment ) ).append( " */ " ); } buf.append( "select " ); if ( distinct ) { diff --git a/hibernate-core/src/main/java/org/hibernate/sql/Select.java b/hibernate-core/src/main/java/org/hibernate/sql/Select.java index e8b0aa4f3f38..e497d7839339 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/Select.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/Select.java @@ -40,7 +40,7 @@ public Select(Dialect dialect) { public String toStatementString() { StringBuilder buf = new StringBuilder(guesstimatedBufferSize); if ( StringHelper.isNotEmpty(comment) ) { - buf.append("/* ").append(comment).append(" */ "); + buf.append( "/* " ).append( Dialect.escapeComment( comment ) ).append( " */ " ); } buf.append("select ").append(selectClause) diff --git a/hibernate-core/src/main/java/org/hibernate/sql/SimpleSelect.java b/hibernate-core/src/main/java/org/hibernate/sql/SimpleSelect.java index f27f407b2ceb..4c574cf5a6f2 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/SimpleSelect.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/SimpleSelect.java @@ -148,7 +148,7 @@ public String toStatementString() { ); if ( comment != null ) { - buf.append( "/* " ).append( comment ).append( " */ " ); + buf.append( "/* " ).append( Dialect.escapeComment( comment ) ).append( " */ " ); } buf.append( "select " ); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/Update.java b/hibernate-core/src/main/java/org/hibernate/sql/Update.java index 93611d73a4fe..67ac8d8faef5 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/Update.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/Update.java @@ -166,7 +166,7 @@ public Update setWhere(String where) { public String toStatementString() { StringBuilder buf = new StringBuilder( (columns.size() * 15) + tableName.length() + 10 ); if ( comment!=null ) { - buf.append( "/* " ).append( comment ).append( " */ " ); + buf.append( "/* " ).append( Dialect.escapeComment( comment ) ).append( " */ " ); } buf.append( "update " ).append( tableName ).append( " set " ); boolean assignmentsAppended = false; diff --git a/hibernate-core/src/test/java/org/hibernate/test/comments/TestEntity.java b/hibernate-core/src/test/java/org/hibernate/test/comments/TestEntity.java new file mode 100644 index 000000000000..7c425becc49e --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/comments/TestEntity.java @@ -0,0 +1,46 @@ +/* + * 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 . + */ +package org.hibernate.test.comments; + +import javax.persistence.Entity; +import javax.persistence.Id; + +/** + * @author Andrea Boriero + */ +@Entity +public class TestEntity { + @Id + private String id; + + private String value; + + public TestEntity() { + + } + + public TestEntity(String id, String value) { + this.id = id; + this.value = value; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/comments/TestEntity2.java b/hibernate-core/src/test/java/org/hibernate/test/comments/TestEntity2.java new file mode 100644 index 000000000000..58b626df6039 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/comments/TestEntity2.java @@ -0,0 +1,37 @@ +/* + * 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 . + */ +package org.hibernate.test.comments; + +import javax.persistence.Entity; +import javax.persistence.Id; + +/** + * @author Andrea Boriero + */ +@Entity +public class TestEntity2 { + @Id + private String id; + + private String value; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/comments/UseSqlCommentTest.java b/hibernate-core/src/test/java/org/hibernate/test/comments/UseSqlCommentTest.java new file mode 100644 index 000000000000..2bd6adf8c8c3 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/comments/UseSqlCommentTest.java @@ -0,0 +1,111 @@ +/* + * 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 . + */ +package org.hibernate.test.comments; + +import java.util.List; +import java.util.Map; +import javax.persistence.EntityManager; +import javax.persistence.TypedQuery; +import javax.persistence.criteria.CompoundSelection; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Path; +import javax.persistence.criteria.Root; + +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + +import org.junit.Before; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; +import static org.junit.Assert.assertThat; + +/** + * @author Andrea Boriero + */ +public class UseSqlCommentTest extends BaseEntityManagerFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { TestEntity.class, TestEntity2.class }; + } + + @Override + protected void addMappings(Map settings) { + settings.put( AvailableSettings.USE_SQL_COMMENTS, "true" ); + settings.put( AvailableSettings.FORMAT_SQL, "false" ); + } + + @Before + public void setUp() { + doInJPA( this::entityManagerFactory, entityManager -> { + TestEntity testEntity = new TestEntity(); + testEntity.setId( "test1" ); + testEntity.setValue( "value1" ); + entityManager.persist( testEntity ); + + TestEntity2 testEntity2 = new TestEntity2(); + testEntity2.setId( "test2" ); + testEntity2.setValue( "value2" ); + entityManager.persist( testEntity2 ); + } ); + } + + @Test + public void testIt() { + String appendLiteral = "*/select id as col_0_0_,value as col_1_0_ from testEntity2 where 1=1 or id=?--/*"; + doInJPA( this::entityManagerFactory, entityManager -> { + + List result = findUsingQuery( "test1", appendLiteral, entityManager ); + + TestEntity test1 = result.get( 0 ); + assertThat( test1.getValue(), is( appendLiteral ) ); + } ); + + doInJPA( this::entityManagerFactory, entityManager -> { + + List result = findUsingCriteria( "test1", appendLiteral, entityManager ); + + TestEntity test1 = result.get( 0 ); + assertThat( test1.getValue(), is( appendLiteral ) ); + } ); + } + + public List findUsingCriteria(String id, String appendLiteral, EntityManager entityManager) { + CriteriaBuilder builder = entityManager.getCriteriaBuilder(); + CriteriaQuery criteria = builder.createQuery( TestEntity.class ); + Root root = criteria.from( TestEntity.class ); + + Path idPath = root.get( "id" ); + CompoundSelection selection = builder.construct( + TestEntity.class, + idPath, + builder.literal( appendLiteral ) + ); + criteria.select( selection ); + + criteria.where( builder.equal( idPath, builder.parameter( String.class, "where_id" ) ) ); + + TypedQuery query = entityManager.createQuery( criteria ); + query.setParameter( "where_id", id ); + return query.getResultList(); + } + + public List findUsingQuery(String id, String appendLiteral, EntityManager entityManager) { + TypedQuery query = + entityManager.createQuery( + "select new org.hibernate.test.comments.TestEntity(id, '" + + appendLiteral.replace( "'", "''" ) + + "') from TestEntity where id=:where_id", + TestEntity.class + ); + query.setParameter( "where_id", id ); + return query.getResultList(); + } +}