HHH-11324 - Fix LimitHandler parsing of subqueries in the select clause for SQLServer2005Dialect.
(cherry picked from commit 087729c023
)
This commit is contained in:
parent
6b928f9379
commit
f7eb28bd20
|
@ -8,6 +8,7 @@ package org.hibernate.dialect.pagination;
|
||||||
|
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
|
@ -316,12 +317,29 @@ public class SQLServer2005LimitHandler extends AbstractLimitHandler {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<IgnoreRange> ignoreRangeList = generateIgnoreRanges( matchString );
|
||||||
|
|
||||||
Matcher matcher = pattern.matcher( matchString );
|
Matcher matcher = pattern.matcher( matchString );
|
||||||
matcher.region( fromIndex, matchString.length() );
|
matcher.region( fromIndex, matchString.length() );
|
||||||
|
|
||||||
|
if ( ignoreRangeList.isEmpty() ) {
|
||||||
|
// old behavior where the first match is used if no ignorable ranges
|
||||||
|
// were deduced from the matchString.
|
||||||
if ( matcher.find() && matcher.groupCount() > 0 ) {
|
if ( matcher.find() && matcher.groupCount() > 0 ) {
|
||||||
index = matcher.start();
|
index = matcher.start();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// rather than taking the first match, we now iterate all matches
|
||||||
|
// until we determine a match that isn't considered "ignorable'.
|
||||||
|
while ( matcher.find() && matcher.groupCount() > 0 ) {
|
||||||
|
final int position = matcher.start();
|
||||||
|
if ( !isPositionIgnorable( ignoreRangeList, position ) ) {
|
||||||
|
index = position;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,4 +360,75 @@ public class SQLServer2005LimitHandler extends AbstractLimitHandler {
|
||||||
Pattern.CASE_INSENSITIVE
|
Pattern.CASE_INSENSITIVE
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Geneartes a list of {@code IgnoreRange} objects that represent nested sections of the
|
||||||
|
* provided SQL buffer that should be ignored when performing regular expression matches.
|
||||||
|
*
|
||||||
|
* @param sql The SQL buffer.
|
||||||
|
* @return list of {@code IgnoreRange} objects, never {@code null}.
|
||||||
|
*/
|
||||||
|
private static List<IgnoreRange> generateIgnoreRanges(String sql) {
|
||||||
|
List<IgnoreRange> ignoreRangeList = new ArrayList<IgnoreRange>();
|
||||||
|
|
||||||
|
int depth = 0;
|
||||||
|
int start = -1;
|
||||||
|
for ( int i = 0; i < sql.length(); ++i ) {
|
||||||
|
final char ch = sql.charAt( i );
|
||||||
|
if ( ch == '(' ) {
|
||||||
|
depth++;
|
||||||
|
if ( depth == 1 ) {
|
||||||
|
start = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( ch == ')' ) {
|
||||||
|
if ( depth > 0 ) {
|
||||||
|
if ( depth == 1 ) {
|
||||||
|
ignoreRangeList.add( new IgnoreRange( start, i ) );
|
||||||
|
start = -1;
|
||||||
|
}
|
||||||
|
depth--;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IllegalStateException( "Found an unmatched ')' at position " + i + ": " + sql );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( depth != 0 ) {
|
||||||
|
throw new IllegalStateException( "Unmatched parenthesis in rendered SQL (" + depth + " depth): " + sql );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ignoreRangeList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the specified {@code position} is within the ranges of the {@code ignoreRangeList}.
|
||||||
|
*
|
||||||
|
* @param ignoreRangeList list of {@code IgnoreRange} objects deduced from the SQL buffer.
|
||||||
|
* @param position the position to determine whether is ignorable.
|
||||||
|
* @return {@code true} if the position is to ignored/skipped, {@code false} otherwise.
|
||||||
|
*/
|
||||||
|
private static boolean isPositionIgnorable(List<IgnoreRange> ignoreRangeList, int position) {
|
||||||
|
for ( IgnoreRange ignoreRange : ignoreRangeList ) {
|
||||||
|
if ( ignoreRange.isWithinRange( position ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class IgnoreRange {
|
||||||
|
private int start;
|
||||||
|
private int end;
|
||||||
|
|
||||||
|
IgnoreRange(int start, int end) {
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isWithinRange(int position) {
|
||||||
|
return position >= start && position <= end;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue