HHH-10994 - Relax requirement of 'as' in the alias phrase for the MSSQL LimitHandler implementation.
(cherry picked from commit 714ba62
)
This commit is contained in:
parent
a06cc89cdb
commit
2dc5236a85
|
@ -28,13 +28,16 @@ public class SQLServer2005LimitHandler extends AbstractLimitHandler {
|
|||
private static final String DISTINCT = "distinct";
|
||||
private static final String ORDER_BY = "order by";
|
||||
|
||||
private static final Pattern SELECT_PATTERN = buildShallowIndexPattern( SELECT + "(.)*" );
|
||||
private static final Pattern FROM_PATTERN = buildShallowIndexPattern( FROM );
|
||||
private static final Pattern DISTINCT_PATTERN = buildShallowIndexPattern( DISTINCT );
|
||||
private static final Pattern ORDER_BY_PATTERN = buildShallowIndexPattern( ORDER_BY );
|
||||
private static final Pattern COMMA_PATTERN = buildShallowIndexPattern( "," );
|
||||
final String SELECT_DISTINCT_SPACE = "select distinct ";
|
||||
final String SELECT_SPACE = "select ";
|
||||
|
||||
private static final Pattern ALIAS_PATTERN = Pattern.compile( "(?i)\\sas\\s(.)+$" );
|
||||
private static final Pattern SELECT_PATTERN = buildShallowIndexPattern( SELECT + "(.*)", true );
|
||||
private static final Pattern FROM_PATTERN = buildShallowIndexPattern( FROM, true );
|
||||
private static final Pattern DISTINCT_PATTERN = buildShallowIndexPattern( DISTINCT, true );
|
||||
private static final Pattern ORDER_BY_PATTERN = buildShallowIndexPattern( ORDER_BY, true );
|
||||
private static final Pattern COMMA_PATTERN = buildShallowIndexPattern( ",", false );
|
||||
private static final Pattern ALIAS_PATTERN =
|
||||
Pattern.compile( "\\S+\\s*(\\s(?i)as\\s)\\s*(\\S+)*\\s*$|\\s+(\\S+)$" );
|
||||
|
||||
// Flag indicating whether TOP(?) expression has been added to the original query.
|
||||
private boolean topAdded;
|
||||
|
@ -145,7 +148,7 @@ public class SQLServer2005LimitHandler extends AbstractLimitHandler {
|
|||
*/
|
||||
protected String fillAliasInSelectClause(StringBuilder sb) {
|
||||
final List<String> aliases = new LinkedList<String>();
|
||||
final int startPos = shallowIndexOfPattern( sb, SELECT_PATTERN, 0 );
|
||||
final int startPos = getSelectColumnsStartPosition( sb );
|
||||
int endPos = shallowIndexOfPattern( sb, FROM_PATTERN, startPos );
|
||||
|
||||
int nextComa = startPos;
|
||||
|
@ -201,6 +204,35 @@ public class SQLServer2005LimitHandler extends AbstractLimitHandler {
|
|||
return selectsMultipleColumns ? "*" : StringHelper.join( ", ", aliases.iterator() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the start position for where the column list begins.
|
||||
*
|
||||
* @param sb the string builder sql.
|
||||
* @return the start position where the column list begins.
|
||||
*/
|
||||
private int getSelectColumnsStartPosition(StringBuilder sb) {
|
||||
final int startPos = getSelectStartPosition( sb );
|
||||
// adjustment for 'select distinct ' and 'select '.
|
||||
final String sql = sb.toString().substring( startPos ).toLowerCase();
|
||||
if ( sql.startsWith( SELECT_DISTINCT_SPACE ) ) {
|
||||
return ( startPos + SELECT_DISTINCT_SPACE.length() );
|
||||
}
|
||||
else if ( sql.startsWith( SELECT_SPACE ) ) {
|
||||
return ( startPos + SELECT_SPACE.length() );
|
||||
}
|
||||
return startPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the select start position.
|
||||
*
|
||||
* @param sb the string builder sql.
|
||||
* @return the position where {@code select} is found.
|
||||
*/
|
||||
private int getSelectStartPosition(StringBuilder sb) {
|
||||
return shallowIndexOfPattern( sb, SELECT_PATTERN, 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param expression Select expression.
|
||||
*
|
||||
|
@ -220,11 +252,17 @@ public class SQLServer2005LimitHandler extends AbstractLimitHandler {
|
|||
* @return Column alias.
|
||||
*/
|
||||
private String getAlias(String expression) {
|
||||
// remove any function arguments, if any exist.
|
||||
// 'cast(tab1.col1 as varchar(255)) as col1' -> 'cast as col1'
|
||||
// 'cast(tab1.col1 as varchar(255)) col1 -> 'cast col1'
|
||||
// 'cast(tab1.col1 as varchar(255))' -> 'cast'
|
||||
expression = expression.replaceFirst( "(\\((.)*\\))", "" ).trim();
|
||||
|
||||
// This will match any text provided with:
|
||||
// columnName [[as] alias]
|
||||
final Matcher matcher = ALIAS_PATTERN.matcher( expression );
|
||||
if ( matcher.find() ) {
|
||||
// Taking advantage of Java regular expressions greedy behavior while extracting the last AS keyword.
|
||||
// Note that AS keyword can appear in CAST operator, e.g. 'cast(tab1.col1 as varchar(255)) as col1'.
|
||||
return matcher.group( 0 ).replaceFirst( "(?i)(.)*\\sas\\s", "" ).trim();
|
||||
if ( matcher.find() && matcher.groupCount() > 1 ) {
|
||||
return matcher.group( 1 ) != null ? matcher.group( 2 ) : matcher.group( 3 );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -292,9 +330,16 @@ public class SQLServer2005LimitHandler extends AbstractLimitHandler {
|
|||
* based on the search pattern that is not enclosed in parenthesis.
|
||||
*
|
||||
* @param pattern String search pattern.
|
||||
* @param wordBoundardy whether to apply a word boundary restriction.
|
||||
* @return Compiled {@link Pattern}.
|
||||
*/
|
||||
private static Pattern buildShallowIndexPattern(String pattern) {
|
||||
return Pattern.compile( "(\\b" + pattern + ")(?![^\\(]*\\))", Pattern.CASE_INSENSITIVE );
|
||||
private static Pattern buildShallowIndexPattern(String pattern, boolean wordBoundardy) {
|
||||
return Pattern.compile(
|
||||
"(" +
|
||||
( wordBoundardy ? "\\b" : "" ) +
|
||||
pattern +
|
||||
")(?![^\\(]*\\))",
|
||||
Pattern.CASE_INSENSITIVE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import static org.junit.Assert.assertEquals;
|
|||
*
|
||||
* @author Valotasion Yoryos
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
public class SQLServer2005DialectTestCase extends BaseUnitTestCase {
|
||||
private SQLServer2005Dialect dialect;
|
||||
|
@ -114,6 +115,18 @@ public class SQLServer2005DialectTestCase extends BaseUnitTestCase {
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-10994")
|
||||
public void testGetLimitStringAliasGenerationWithAliasesNoAs() {
|
||||
final String aliasedSQLNoAs = "select column1 c1, column c2, column c3, column c4 from table1";
|
||||
assertEquals(
|
||||
"WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " +
|
||||
"select column1 c1, column c2, column c3, column c4 from table1 ) inner_query ) " +
|
||||
"SELECT c1, c2, c3, c4 FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?",
|
||||
dialect.getLimitHandler().processSql( aliasedSQLNoAs, toRowSelection( 3, 5 ) )
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-7019")
|
||||
public void testGetLimitStringWithSubselect() {
|
||||
|
@ -164,6 +177,32 @@ public class SQLServer2005DialectTestCase extends BaseUnitTestCase {
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-10994")
|
||||
public void testGetLimitStringDistinctWithinAggregationWithoutAlias() {
|
||||
final String distinctInAggregateSQL = "select aggregate_function(distinct p.n) from table849752 p order by f1";
|
||||
|
||||
assertEquals(
|
||||
"WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " +
|
||||
"select TOP(?) aggregate_function(distinct p.n) as page0_ from table849752 p order by f1 ) inner_query ) " +
|
||||
"SELECT page0_ FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?",
|
||||
dialect.getLimitHandler().processSql( distinctInAggregateSQL, toRowSelection( 2, 5 ) )
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-10994")
|
||||
public void testGetLimitStringDistinctWithinAggregationWithAliasNoAs() {
|
||||
final String distinctInAggregateSQL = "select aggregate_function(distinct p.n) f1 from table849752 p order by f1";
|
||||
|
||||
assertEquals(
|
||||
"WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " +
|
||||
"select TOP(?) aggregate_function(distinct p.n) f1 from table849752 p order by f1 ) inner_query ) " +
|
||||
"SELECT f1 FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?",
|
||||
dialect.getLimitHandler().processSql( distinctInAggregateSQL, toRowSelection( 2, 5 ) )
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-7370")
|
||||
public void testGetLimitStringWithMaxOnly() {
|
||||
|
@ -201,6 +240,36 @@ public class SQLServer2005DialectTestCase extends BaseUnitTestCase {
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-10994")
|
||||
public void testGetLimitStringWithCastOperatorWithAliasNoAs() {
|
||||
final String query = "select cast(lc302_doku6_.redniBrojStavke as varchar(255)) f1, lc302_doku6_.dokumentiID f2 " +
|
||||
"from LC302_Dokumenti lc302_doku6_ order by lc302_doku6_.dokumentiID DESC";
|
||||
|
||||
assertEquals(
|
||||
"WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " +
|
||||
"select TOP(?) cast(lc302_doku6_.redniBrojStavke as varchar(255)) f1, lc302_doku6_.dokumentiID f2 " +
|
||||
"from LC302_Dokumenti lc302_doku6_ order by lc302_doku6_.dokumentiID DESC ) inner_query ) " +
|
||||
"SELECT f1, f2 FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?",
|
||||
dialect.getLimitHandler().processSql( query, toRowSelection( 1, 3 ) )
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-10994")
|
||||
public void testGetLimitStringWithCastOperatorWithoutAliases() {
|
||||
final String query = "select cast(lc302_doku6_.redniBrojStavke as varchar(255)), lc302_doku6_.dokumentiID " +
|
||||
"from LC302_Dokumenti lc302_doku6_ order by lc302_doku6_.dokumentiID DESC";
|
||||
|
||||
assertEquals(
|
||||
"WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " +
|
||||
"select TOP(?) cast(lc302_doku6_.redniBrojStavke as varchar(255)) as page0_, lc302_doku6_.dokumentiID as page1_ " +
|
||||
"from LC302_Dokumenti lc302_doku6_ order by lc302_doku6_.dokumentiID DESC ) inner_query ) " +
|
||||
"SELECT page0_, page1_ FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?",
|
||||
dialect.getLimitHandler().processSql( query, toRowSelection( 1, 3 ) )
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-8007")
|
||||
public void testGetLimitStringSelectingMultipleColumnsFromSeveralTables() {
|
||||
|
|
Loading…
Reference in New Issue