HHH-15745 Change string literal handling in HQL lexer

This commit is contained in:
Marco Belladelli 2022-12-06 17:39:25 +01:00 committed by Christian Beikov
parent 1109dfbb1c
commit f2576d6b87
5 changed files with 89 additions and 50 deletions

View File

@ -75,10 +75,13 @@ HEX_LITERAL : '0' [xX] HEX_DIGIT+ LONG_SUFFIX?;
fragment SINGLE_QUOTE : '\'';
fragment DOUBLE_QUOTE : '"';
STRING_LITERAL
: DOUBLE_QUOTE ( ESCAPE_SEQUENCE | DOUBLE_QUOTE DOUBLE_QUOTE | ~('"') )* DOUBLE_QUOTE
| SINGLE_QUOTE ( ESCAPE_SEQUENCE | SINGLE_QUOTE SINGLE_QUOTE | ~('\'') )* SINGLE_QUOTE
;
STRING_LITERAL : SINGLE_QUOTE ( SINGLE_QUOTE SINGLE_QUOTE | ~('\'') )* SINGLE_QUOTE;
JAVA_STRING_LITERAL
: DOUBLE_QUOTE ( ESCAPE_SEQUENCE | ~('"') )* DOUBLE_QUOTE
| [jJ] SINGLE_QUOTE ( ESCAPE_SEQUENCE | ~('\'') )* SINGLE_QUOTE
| [jJ] DOUBLE_QUOTE ( ESCAPE_SEQUENCE | ~('\'') )* DOUBLE_QUOTE
;
fragment BACKSLASH : '\\';
@ -96,6 +99,7 @@ UNICODE_ESCAPE
BINARY_LITERAL
: [xX] SINGLE_QUOTE (HEX_DIGIT HEX_DIGIT)* SINGLE_QUOTE
| [xX] DOUBLE_QUOTE (HEX_DIGIT HEX_DIGIT)* DOUBLE_QUOTE
;
// ESCAPE start tokens

View File

@ -665,7 +665,7 @@ inList
* A single character used to escape the '_' and '%' wildcards in a 'like' pattern
*/
likeEscape
: ESCAPE (STRING_LITERAL | parameter)
: ESCAPE (STRING_LITERAL | JAVA_STRING_LITERAL | parameter)
;
@ -823,6 +823,7 @@ searchedCaseWhen
*/
literal
: STRING_LITERAL
| JAVA_STRING_LITERAL
| NULL
| booleanLiteral
| numericLiteral

View File

@ -74,7 +74,7 @@ public final class QuotingHelper {
final int end = text.length() - 1;
final char delimiter = text.charAt( 0 );
assert delimiter == text.charAt( end );
// Unescape the parsed literal and handle escape sequences
// Unescape the parsed literal
final StringBuilder sb = new StringBuilder( text.length() - 2 );
for ( int i = 1; i < end; i++ ) {
char c = text.charAt( i );
@ -89,48 +89,6 @@ public final class QuotingHelper {
i++;
}
break;
case '\\':
if ( ( i + 1 ) < end ) {
char nextChar = text.charAt( ++i );
switch ( nextChar ) {
case 'b':
c = '\b';
break;
case 't':
c = '\t';
break;
case 'n':
c = '\n';
break;
case 'f':
c = '\f';
break;
case 'r':
c = '\r';
break;
case '\\':
c = '\\';
break;
case '\'':
c = '\'';
break;
case '"':
c = '"';
break;
case '`':
c = '`';
break;
case 'u':
c = (char) Integer.parseInt( text.substring( i + 1, i + 5 ), 16 );
i += 4;
break;
default:
sb.append( '\\' );
c = nextChar;
break;
}
}
break;
default:
break;
}
@ -138,4 +96,60 @@ public final class QuotingHelper {
}
return sb.toString();
}
public static String unquoteJavaStringLiteral(String text) {
assert text.length() > 1;
final char firstChar = text.charAt( 0 );
final int start = firstChar == 'j' || firstChar == 'J' ? 1 : 0;
final int end = text.length() - 1;
final char delimiter = text.charAt( start );
assert delimiter == text.charAt( end );
// Handle escape sequences
final StringBuilder sb = new StringBuilder( text.length() - ( start + 2 ) );
for ( int i = start + 1; i < end; i++ ) {
char c = text.charAt( i );
if ( c == '\\' && ( i + 1 ) < end ) {
char nextChar = text.charAt( ++i );
switch ( nextChar ) {
case 'b':
c = '\b';
break;
case 't':
c = '\t';
break;
case 'n':
c = '\n';
break;
case 'f':
c = '\f';
break;
case 'r':
c = '\r';
break;
case '\\':
c = '\\';
break;
case '\'':
c = '\'';
break;
case '"':
c = '"';
break;
case '`':
c = '`';
break;
case 'u':
c = (char) Integer.parseInt( text.substring( i + 1, i + 5 ), 16 );
i += 4;
break;
default:
sb.append( '\\' );
c = nextChar;
break;
}
}
sb.append( c );
}
return sb.toString();
}
}

View File

@ -3275,6 +3275,8 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
switch ( node.getSymbol().getType() ) {
case HqlParser.STRING_LITERAL:
return stringLiteral( node.getText() );
case HqlParser.JAVA_STRING_LITERAL:
return javaStringLiteral( node.getText() );
case HqlParser.INTEGER_LITERAL:
return integerOrLongLiteral( node.getText() );
case HqlParser.LONG_LITERAL:
@ -3587,6 +3589,15 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
);
}
private SqmLiteral<String> javaStringLiteral(String text) {
String unquoted = QuotingHelper.unquoteJavaStringLiteral( text );
return new SqmLiteral<>(
unquoted,
resolveExpressibleTypeBasic( String.class ),
creationContext.getNodeBuilder()
);
}
private SqmLiteral<byte[]> binaryLiteral(String text) {
return new SqmLiteral<>(
PrimitiveByteArrayJavaType.INSTANCE.fromString(

View File

@ -60,6 +60,17 @@ public class LiteralTests {
);
}
@Test
public void testJavaString(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
assertThat( session.createQuery( "select \"\\n\"" ).getSingleResult(), is( "\n" ) );
assertThat( session.createQuery( "select J'\\n'" ).getSingleResult(), is( "\n" ) );
assertThat( session.createQuery( "select J'\\''" ).getSingleResult(), is( "'" ) );
}
);
}
@Test
public void testJdbcTimeLiteral(SessionFactoryScope scope) {
scope.inTransaction(
@ -315,6 +326,4 @@ public class LiteralTests {
}
);
}
}