From 7236123b0cfd15d23f8c6533619d093dee625d45 Mon Sep 17 00:00:00 2001 From: Michael Schnell Date: Sat, 23 Apr 2016 12:57:01 +0200 Subject: [PATCH] HHH-1237 Escaping colon in queries --- .../engine/query/spi/ParameterParser.java | 6 +- .../MySQLSetVariableEscapeColonTest.java | 66 +++++++++++++++++++ .../engine/query/ParameterParserTest.java | 46 ++++++++++++- 3 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/engine/query/MySQLSetVariableEscapeColonTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/engine/query/spi/ParameterParser.java b/hibernate-core/src/main/java/org/hibernate/engine/query/spi/ParameterParser.java index 1cb9f75478..f2cdbee110 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/query/spi/ParameterParser.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/query/spi/ParameterParser.java @@ -159,7 +159,11 @@ public class ParameterParser { } // otherwise else { - if ( c == ':' ) { + if ( c == ':' && indx < stringLength - 1 && sqlString.charAt( indx + 1 ) == ':') { + // colon character has been escaped + recognizer.other( c ); + indx++; + } else if ( c == ':' ) { // named parameter final int right = StringHelper.firstIndexOfChar( sqlString, ParserHelper.HQL_SEPARATORS_BITSET, indx + 1 ); final int chopLocation = right < 0 ? sqlString.length() : right; diff --git a/hibernate-core/src/test/java/org/hibernate/engine/query/MySQLSetVariableEscapeColonTest.java b/hibernate-core/src/test/java/org/hibernate/engine/query/MySQLSetVariableEscapeColonTest.java new file mode 100644 index 0000000000..802773b014 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/engine/query/MySQLSetVariableEscapeColonTest.java @@ -0,0 +1,66 @@ +/* + * 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.engine.query; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; + +import org.hibernate.Session; +import org.hibernate.dialect.MySQL5Dialect; +import org.hibernate.jdbc.Work; + +import org.hibernate.testing.RequiresDialect; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * @author Vlad Mihalcea + */ +@RequiresDialect(MySQL5Dialect.class) +@TestForIssue( jiraKey = "HHH-1237") +public class MySQLSetVariableEscapeColonTest extends BaseCoreFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { }; + } + + @Test + public void testBoundedLongStringAccess() { + + Session s = openSession(); + s.beginTransaction(); + try { + s.doWork( new Work() { + @Override + public void execute(Connection connection) throws SQLException { + Statement statement = connection.createStatement(); + try { + statement.executeUpdate( "SET @a='test'" ); + } + finally { + statement.close(); + } + } + } ); + Object[] result = (Object[]) session.createSQLQuery( "SELECT @a, (@a::=20) FROM dual" ).uniqueResult(); + assertEquals("test", result[0]); + assertEquals(20, ((Number) result[1]).intValue()); + + s.getTransaction().commit(); + } + finally { + s.close(); + } + } + +} + diff --git a/hibernate-core/src/test/java/org/hibernate/engine/query/ParameterParserTest.java b/hibernate-core/src/test/java/org/hibernate/engine/query/ParameterParserTest.java index 33928f4a00..a9cc874c59 100644 --- a/hibernate-core/src/test/java/org/hibernate/engine/query/ParameterParserTest.java +++ b/hibernate-core/src/test/java/org/hibernate/engine/query/ParameterParserTest.java @@ -8,20 +8,22 @@ package org.hibernate.engine.query; import org.hibernate.engine.query.spi.ParamLocationRecognizer; import org.hibernate.engine.query.spi.ParameterParser; +import org.hibernate.engine.query.spi.ParameterParser.Recognizer; -import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.hibernate.testing.TestForIssue; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; /** * Unit tests of the ParameterParser class * * @author Steve Ebersole */ -public class ParameterParserTest extends BaseUnitTestCase { +public class ParameterParserTest { @Test public void testEscapeCallRecognition() { assertTrue( ParameterParser.startsWithEscapeCallTemplate( "{ ? = call abc(?) }" ) ); @@ -75,4 +77,44 @@ public class ParameterParserTest extends BaseUnitTestCase { assertTrue(recognizer.getNamedParameterDescriptionMap().containsKey("param")); } + + @Test + @TestForIssue( jiraKey = "HHH-1237") + public void testParseColonCharacterEscaped() { + final StringBuilder captured = new StringBuilder(); + Recognizer recognizer = new Recognizer() { + @Override + public void outParameter(int position) { + fail(); + } + @Override + public void ordinalParameter(int position) { + fail(); + } + @Override + public void namedParameter(String name, int position) { + fail(); + } + @Override + public void jpaPositionalParameter(String name, int position) { + fail(); + } + @Override + public void other(char character) { + captured.append(character); + } + }; + ParameterParser.parse("SELECT @a,(@a::=20) FROM tbl_name", recognizer); + assertEquals("SELECT @a,(@a:=20) FROM tbl_name", captured.toString()); + } + + @Test + public void testParseNamedParameter() { + ParamLocationRecognizer recognizer = new ParamLocationRecognizer(); + ParameterParser.parse("from Stock s where s.stockCode = :stockCode and s.xyz = :pxyz", recognizer); + assertTrue(recognizer.getNamedParameterDescriptionMap().containsKey("stockCode")); + assertTrue(recognizer.getNamedParameterDescriptionMap().containsKey("pxyz")); + assertEquals( 2, recognizer.getNamedParameterDescriptionMap().size() ); + } + }