Skip to content

Commit

Permalink
HHH-19052 Using lookahead StringTokenizer when analyzing part of SQL …
Browse files Browse the repository at this point in the history
…query prefixed by literal prefix
  • Loading branch information
cigaly committed Jan 18, 2025
1 parent 8ad3b35 commit fbf70fe
Showing 1 changed file with 29 additions and 6 deletions.
35 changes: 29 additions & 6 deletions hibernate-core/src/main/java/org/hibernate/sql/Template.java
Original file line number Diff line number Diff line change
Expand Up @@ -194,22 +194,27 @@ else if ( LITERAL_PREFIXES.contains( lcToken ) ) {
continue;
}
else if ( nextToken != null && Character.isWhitespace( nextToken.charAt( 0 ) ) ) {
final StringTokenizer lookahead = lookahead( sqlWhereString, symbols, tokens);
String lookaheadToken = lookahead.hasMoreTokens() ? lookahead.nextToken() : null;
final StringBuilder additionalTokens = new StringBuilder();
TimeZoneTokens possibleNextToken = null;
do {
possibleNextToken = possibleNextToken == null
? TimeZoneTokens.getPossibleNextTokens( lcToken )
: possibleNextToken.nextToken();
do {
additionalTokens.append( nextToken );
hasMore = tokens.hasMoreTokens();
nextToken = tokens.nextToken();
} while ( nextToken != null && Character.isWhitespace( nextToken.charAt( 0 ) ) );
} while ( nextToken != null && possibleNextToken.isToken( nextToken ) );
if ( "'".equals( nextToken ) ) {
additionalTokens.append( lookaheadToken );
lookaheadToken = lookahead.hasMoreTokens() ? lookahead.nextToken() : null;
} while ( lookaheadToken != null && Character.isWhitespace( lookaheadToken.charAt( 0 ) ) );
} while ( lookaheadToken != null && possibleNextToken.isToken( lookaheadToken ) );
if ( "'".equals( lookaheadToken ) ) {
// Don't prefix a literal
result.append( token );
result.append( additionalTokens );
while (tokens.countTokens() > lookahead.countTokens()) {
hasMore = tokens.hasMoreTokens();
nextToken = hasMore ? tokens.nextToken() : null;
}
continue;
}
else {
Expand Down Expand Up @@ -401,6 +406,24 @@ else if ( inFromClause && ",".equals(lcToken) ) {
return result.toString();
}

/**
* Clone the given token stream, returning a token stream which begins
* from the next token.
*
* @param sql the full SQL we are scanning
* @param symbols the delimiter symbols
* @param tokens the current token stream
* @return a cloned token stream
*/
private static StringTokenizer lookahead(String sql, String symbols, StringTokenizer tokens) {
final StringTokenizer lookahead =
new StringTokenizer( sql, symbols, true );
while ( lookahead.countTokens() > tokens.countTokens() + 1) {
lookahead.nextToken();
}
return lookahead;
}

private enum TimeZoneTokens {
NONE,
WITH,
Expand Down

0 comments on commit fbf70fe

Please sign in to comment.