HHH-18461 Fix native query doesn't respect `query.setFirstResult(0)`

Align to JPQL query, generated sql should contain `offset ? rows` and pass `0` as parameter.
This commit is contained in:
Yanming Zhou 2024-08-05 17:06:54 +08:00
parent afca93158e
commit b80d21b233
9 changed files with 31 additions and 28 deletions

View File

@ -48,7 +48,7 @@ public class AltibaseDialectTestCase extends BaseUnitTestCase {
public void testSelectWithLimitOnly() { public void testSelectWithLimitOnly() {
assertEquals( "select c1, c2 from t1 order by c1, c2 desc limit ?", assertEquals( "select c1, c2 from t1 order by c1, c2 desc limit ?",
dialect.getLimitHandler().processSql("select c1, c2 from t1 order by c1, c2 desc", dialect.getLimitHandler().processSql("select c1, c2 from t1 order by c1, c2 desc",
toRowSelection( 0, 15 ) ).toLowerCase( Locale.ROOT)); toRowSelection( null, 15 ) ).toLowerCase( Locale.ROOT));
} }
@Test @Test
@ -65,7 +65,7 @@ public class AltibaseDialectTestCase extends BaseUnitTestCase {
null ).toLowerCase(Locale.ROOT)); null ).toLowerCase(Locale.ROOT));
} }
private Limit toRowSelection(int firstRow, int maxRows) { private Limit toRowSelection(Integer firstRow, Integer maxRows) {
Limit selection = new Limit(); Limit selection = new Limit();
selection.setFirstRow( firstRow ); selection.setFirstRow( firstRow );
selection.setMaxRows( maxRows ); selection.setMaxRows( maxRows );

View File

@ -42,7 +42,7 @@ public class DerbyDialectTestCase {
final String input = "select * from tablename t where t.cat = 5"; final String input = "select * from tablename t where t.cat = 5";
final String expected = "select * from tablename t where t.cat = 5 fetch first ? rows only"; final String expected = "select * from tablename t where t.cat = 5 fetch first ? rows only";
final String actual = new DerbyDialect().getLimitHandler().processSql( input, toRowSelection( 0, limit ) ); final String actual = new DerbyDialect().getLimitHandler().processSql( input, toRowSelection( null, limit ) );
assertEquals( expected, actual ); assertEquals( expected, actual );
} }
@ -101,7 +101,7 @@ public class DerbyDialectTestCase {
scope.inSession( s -> Assertions.assertEquals( 69, s.createSelectionQuery( "select count from Constrained", int.class).getSingleResult())); scope.inSession( s -> Assertions.assertEquals( 69, s.createSelectionQuery( "select count from Constrained", int.class).getSingleResult()));
} }
private Limit toRowSelection(int firstRow, int maxRows) { private Limit toRowSelection(Integer firstRow, Integer maxRows) {
Limit selection = new Limit(); Limit selection = new Limit();
selection.setFirstRow( firstRow ); selection.setFirstRow( firstRow );
selection.setMaxRows( maxRows ); selection.setMaxRows( maxRows );

View File

@ -29,7 +29,7 @@ public class DerbyLegacyDialectTestCase extends BaseUnitTestCase {
final String input = "select * from tablename t where t.cat = 5"; final String input = "select * from tablename t where t.cat = 5";
final String expected = "select * from tablename t where t.cat = 5 fetch first " + limit + " rows only"; final String expected = "select * from tablename t where t.cat = 5 fetch first " + limit + " rows only";
final String actual = new DerbyLegacyDialect( DatabaseVersion.make( 10, 5 ) ).getLimitHandler().processSql( input, toRowSelection( 0, limit ) ); final String actual = new DerbyLegacyDialect( DatabaseVersion.make( 10, 5 ) ).getLimitHandler().processSql( input, toRowSelection( null, limit ) );
assertEquals( expected, actual ); assertEquals( expected, actual );
} }
@ -84,7 +84,7 @@ public class DerbyLegacyDialectTestCase extends BaseUnitTestCase {
assertEquals( expected, actual ); assertEquals( expected, actual );
} }
private Limit toRowSelection(int firstRow, int maxRows) { private Limit toRowSelection(Integer firstRow, Integer maxRows) {
Limit selection = new Limit(); Limit selection = new Limit();
selection.setFirstRow( firstRow ); selection.setFirstRow( firstRow );
selection.setMaxRows( maxRows ); selection.setMaxRows( maxRows );

View File

@ -20,15 +20,15 @@ class FirebirdDialectTest {
@ParameterizedTest @ParameterizedTest
@CsvSource(useHeadersInDisplayName = true, value = { @CsvSource(useHeadersInDisplayName = true, value = {
"major, minor, offset, limit, expectedSQL", "major, minor, offset, limit, expectedSQL",
"2, 5, 0, 10, select first ? * from tablename t where t.cat = 5", "2, 5, , 10, select first ? * from tablename t where t.cat = 5",
"2, 5, 10, 0, select skip ? * from tablename t where t.cat = 5", "2, 5, 10, 0, select skip ? * from tablename t where t.cat = 5",
"2, 5, 5, 10, select first ? skip ? * from tablename t where t.cat = 5", "2, 5, 5, 10, select first ? skip ? * from tablename t where t.cat = 5",
"3, 0, 0, 10, select * from tablename t where t.cat = 5 fetch first ? rows only", "3, 0, , 10, select * from tablename t where t.cat = 5 fetch first ? rows only",
"3, 0, 10, 0, select * from tablename t where t.cat = 5 offset ? rows", "3, 0, 10, 0, select * from tablename t where t.cat = 5 offset ? rows",
"3, 0, 5, 10, select * from tablename t where t.cat = 5 offset ? rows fetch next ? rows only" "3, 0, 5, 10, select * from tablename t where t.cat = 5 offset ? rows fetch next ? rows only"
}) })
@JiraKey( "HHH-18213" ) @JiraKey( "HHH-18213" )
void insertOffsetLimitClause(int major, int minor, int offset, int limit, String expectedSql) { void insertOffsetLimitClause(int major, int minor, Integer offset, Integer limit, String expectedSql) {
String input = "select * from tablename t where t.cat = 5"; String input = "select * from tablename t where t.cat = 5";
FirebirdDialect dialect = new FirebirdDialect( DatabaseVersion.make( major, minor ) ); FirebirdDialect dialect = new FirebirdDialect( DatabaseVersion.make( major, minor ) );
String actual = dialect.getLimitHandler().processSql( input, new Limit( offset, limit ) ); String actual = dialect.getLimitHandler().processSql( input, new Limit( offset, limit ) );

View File

@ -168,7 +168,7 @@ public class SQLServer2005DialectTestCase extends BaseUnitTestCase {
"select top(?) col0_.CONTENTID as CONTENT1_12_ " + "select top(?) col0_.CONTENTID as CONTENT1_12_ " +
"where col0_.CONTENTTYPE='PAGE' and (col0_.CONTENTID in " + "where col0_.CONTENTTYPE='PAGE' and (col0_.CONTENTID in " +
"(select distinct col2_.PREVVER from CONTENT col2_ where (col2_.PREVVER is not null)))", "(select distinct col2_.PREVVER from CONTENT col2_ where (col2_.PREVVER is not null)))",
dialect.getLimitHandler().processSql( selectDistinctSubselectSQL, toRowSelection( 0, 5 ) ) dialect.getLimitHandler().processSql( selectDistinctSubselectSQL, toRowSelection( null, 5 ) )
); );
} }
@ -254,7 +254,7 @@ public class SQLServer2005DialectTestCase extends BaseUnitTestCase {
assertEquals( assertEquals(
"select top(?) product2x0_.id as id0_, product2x0_.description as descript2_0_ " + "select top(?) product2x0_.id as id0_, product2x0_.description as descript2_0_ " +
"from Product2 product2x0_ order by product2x0_.id", "from Product2 product2x0_ order by product2x0_.id",
dialect.getLimitHandler().processSql( query, toRowSelection( 0, 1 ) ) dialect.getLimitHandler().processSql( query, toRowSelection( null, 1 ) )
); );
final String distinctQuery = "select distinct product2x0_.id as id0_, product2x0_.description as descript2_0_ " + final String distinctQuery = "select distinct product2x0_.id as id0_, product2x0_.description as descript2_0_ " +
@ -263,7 +263,7 @@ public class SQLServer2005DialectTestCase extends BaseUnitTestCase {
assertEquals( assertEquals(
"select distinct top(?) product2x0_.id as id0_, product2x0_.description as descript2_0_ " + "select distinct top(?) product2x0_.id as id0_, product2x0_.description as descript2_0_ " +
"from Product2 product2x0_ order by product2x0_.id", "from Product2 product2x0_ order by product2x0_.id",
dialect.getLimitHandler().processSql( distinctQuery, toRowSelection( 0, 5 ) ) dialect.getLimitHandler().processSql( distinctQuery, toRowSelection( null, 5 ) )
); );
} }
@ -406,14 +406,14 @@ public class SQLServer2005DialectTestCase extends BaseUnitTestCase {
assertEquals( assertEquals(
"select top(?) t1.c1 as col_0_0, (select case when count(t2.c1)>0 then 'ADDED' else 'UNMODIFIED' end from table2 t2 WHERE (t2.c1 in (?))) as col_1_0 from table1 t1 WHERE 1=1 ORDER BY t1.c1 ASC", "select top(?) t1.c1 as col_0_0, (select case when count(t2.c1)>0 then 'ADDED' else 'UNMODIFIED' end from table2 t2 WHERE (t2.c1 in (?))) as col_1_0 from table1 t1 WHERE 1=1 ORDER BY t1.c1 ASC",
dialect.getLimitHandler().processSql( query, toRowSelection( 0, 5 ) ) dialect.getLimitHandler().processSql( query, toRowSelection( null, 5 ) )
); );
} }
@Test @Test
@TestForIssue(jiraKey = "HHH-8916") @TestForIssue(jiraKey = "HHH-8916")
public void testGetLimitStringUsingCTEQueryNoOffset() { public void testGetLimitStringUsingCTEQueryNoOffset() {
Limit selection = toRowSelection( 0, 5 ); Limit selection = toRowSelection( null, 5 );
// test top-based CTE with single CTE query_ definition with no odd formatting // test top-based CTE with single CTE query_ definition with no odd formatting
final String query1 = "WITH a (c1, c2) AS (SELECT c1, c2 FROM t) SELECT c1, c2 FROM a"; final String query1 = "WITH a (c1, c2) AS (SELECT c1, c2 FROM t) SELECT c1, c2 FROM a";
@ -635,7 +635,7 @@ public class SQLServer2005DialectTestCase extends BaseUnitTestCase {
assertEquals( expectedLockHint, lockHint ); assertEquals( expectedLockHint, lockHint );
} }
private Limit toRowSelection(int firstRow, int maxRows) { private Limit toRowSelection(Integer firstRow, Integer maxRows) {
Limit selection = new Limit(); Limit selection = new Limit();
selection.setFirstRow( firstRow ); selection.setFirstRow( firstRow );
selection.setMaxRows( maxRows ); selection.setMaxRows( maxRows );

View File

@ -170,7 +170,7 @@ public class SQLServer2008DialectTestCase extends BaseUnitTestCase {
"select top(?) col0_.CONTENTID as CONTENT1_12_ " + "select top(?) col0_.CONTENTID as CONTENT1_12_ " +
"where col0_.CONTENTTYPE='PAGE' and (col0_.CONTENTID in " + "where col0_.CONTENTTYPE='PAGE' and (col0_.CONTENTID in " +
"(select distinct col2_.PREVVER from CONTENT col2_ where (col2_.PREVVER is not null)))", "(select distinct col2_.PREVVER from CONTENT col2_ where (col2_.PREVVER is not null)))",
dialect.getLimitHandler().processSql( selectDistinctSubselectSQL, toRowSelection( 0, 5 ) ) dialect.getLimitHandler().processSql( selectDistinctSubselectSQL, toRowSelection( null, 5 ) )
); );
} }
@ -256,7 +256,7 @@ public class SQLServer2008DialectTestCase extends BaseUnitTestCase {
assertEquals( assertEquals(
"select top(?) product2x0_.id as id0_, product2x0_.description as descript2_0_ " + "select top(?) product2x0_.id as id0_, product2x0_.description as descript2_0_ " +
"from Product2 product2x0_ order by product2x0_.id", "from Product2 product2x0_ order by product2x0_.id",
dialect.getLimitHandler().processSql( query, toRowSelection( 0, 1 ) ) dialect.getLimitHandler().processSql( query, toRowSelection( null, 1 ) )
); );
final String distinctQuery = "select distinct product2x0_.id as id0_, product2x0_.description as descript2_0_ " + final String distinctQuery = "select distinct product2x0_.id as id0_, product2x0_.description as descript2_0_ " +
@ -265,7 +265,7 @@ public class SQLServer2008DialectTestCase extends BaseUnitTestCase {
assertEquals( assertEquals(
"select distinct top(?) product2x0_.id as id0_, product2x0_.description as descript2_0_ " + "select distinct top(?) product2x0_.id as id0_, product2x0_.description as descript2_0_ " +
"from Product2 product2x0_ order by product2x0_.id", "from Product2 product2x0_ order by product2x0_.id",
dialect.getLimitHandler().processSql( distinctQuery, toRowSelection( 0, 5 ) ) dialect.getLimitHandler().processSql( distinctQuery, toRowSelection( null, 5 ) )
); );
} }
@ -408,14 +408,14 @@ public class SQLServer2008DialectTestCase extends BaseUnitTestCase {
assertEquals( assertEquals(
"select top(?) t1.c1 as col_0_0, (select case when count(t2.c1)>0 then 'ADDED' else 'UNMODIFIED' end from table2 t2 WHERE (t2.c1 in (?))) as col_1_0 from table1 t1 WHERE 1=1 ORDER BY t1.c1 ASC", "select top(?) t1.c1 as col_0_0, (select case when count(t2.c1)>0 then 'ADDED' else 'UNMODIFIED' end from table2 t2 WHERE (t2.c1 in (?))) as col_1_0 from table1 t1 WHERE 1=1 ORDER BY t1.c1 ASC",
dialect.getLimitHandler().processSql( query, toRowSelection( 0, 5 ) ) dialect.getLimitHandler().processSql( query, toRowSelection( null, 5 ) )
); );
} }
@Test @Test
@JiraKey("HHH-8916") @JiraKey("HHH-8916")
public void testGetLimitStringUsingCTEQueryNoOffset() { public void testGetLimitStringUsingCTEQueryNoOffset() {
Limit selection = toRowSelection( 0, 5 ); Limit selection = toRowSelection( null, 5 );
// test top-based CTE with single CTE query_ definition with no odd formatting // test top-based CTE with single CTE query_ definition with no odd formatting
final String query1 = "WITH a (c1, c2) AS (SELECT c1, c2 FROM t) SELECT c1, c2 FROM a"; final String query1 = "WITH a (c1, c2) AS (SELECT c1, c2 FROM t) SELECT c1, c2 FROM a";
@ -637,7 +637,7 @@ public class SQLServer2008DialectTestCase extends BaseUnitTestCase {
assertEquals( expectedLockHint, lockHint ); assertEquals( expectedLockHint, lockHint );
} }
private Limit toRowSelection(int firstRow, int maxRows) { private Limit toRowSelection(Integer firstRow, Integer maxRows) {
Limit selection = new Limit(); Limit selection = new Limit();
selection.setFirstRow( firstRow ); selection.setFirstRow( firstRow );
selection.setMaxRows( maxRows ); selection.setMaxRows( maxRows );

View File

@ -230,8 +230,7 @@ public abstract class AbstractLimitHandler implements LimitHandler {
*/ */
public static boolean hasFirstRow(Limit limit) { public static boolean hasFirstRow(Limit limit) {
return limit != null return limit != null
&& limit.getFirstRow() != null && limit.getFirstRow() != null;
&& limit.getFirstRow() > 0;
} }
/** /**

View File

@ -50,7 +50,7 @@ public abstract class AbstractLimitHandlerTest {
protected abstract LimitHandler getLimitHandler(); protected abstract LimitHandler getLimitHandler();
protected Limit getLimit() { protected Limit getLimit() {
return new Limit(0, 10); return new Limit(null, 10);
} }
protected String getLimitClause() { protected String getLimitClause() {
@ -64,9 +64,13 @@ public abstract class AbstractLimitHandlerTest {
} }
else if (hasFirstRow(limit)) { else if (hasFirstRow(limit)) {
return " offset " + (oflh.supportsVariableLimit() ? "?" : String.valueOf(limit.getFirstRow())) + " rows"; return " offset " + (oflh.supportsVariableLimit() ? "?" : String.valueOf(limit.getFirstRow())) + " rows";
} else { }
else if (hasMaxRows(limit)) {
return " fetch first " + (oflh.supportsVariableLimit() ? "?" : String.valueOf(limit.getMaxRows())) + " rows only"; return " fetch first " + (oflh.supportsVariableLimit() ? "?" : String.valueOf(limit.getMaxRows())) + " rows only";
} }
else {
return "";
}
} }
return " limit ?"; return " limit ?";
} }

View File

@ -45,7 +45,7 @@ public class SQLServer2012DialectTestCase extends BaseUnitTestCase {
final String input = "select distinct f1 as f53245 from table846752 order by f234, f67 desc"; final String input = "select distinct f1 as f53245 from table846752 order by f234, f67 desc";
assertEquals( assertEquals(
input + " offset 0 rows fetch first ? rows only", input + " offset 0 rows fetch first ? rows only",
dialect.getLimitHandler().processSql( input, toRowSelection( 0, 10 ) ).toLowerCase( Locale.ROOT ) dialect.getLimitHandler().processSql( input, toRowSelection( null, 10 ) ).toLowerCase( Locale.ROOT )
); );
} }
@ -65,7 +65,7 @@ public class SQLServer2012DialectTestCase extends BaseUnitTestCase {
final String input = "select f1 from table"; final String input = "select f1 from table";
assertEquals( assertEquals(
"select f1 from table order by @@version offset 0 rows fetch first ? rows only", "select f1 from table order by @@version offset 0 rows fetch first ? rows only",
dialect.getLimitHandler().processSql( input, toRowSelection( 0, 10 ) ).toLowerCase( Locale.ROOT ) dialect.getLimitHandler().processSql( input, toRowSelection( null, 10 ) ).toLowerCase( Locale.ROOT )
); );
} }
@ -79,7 +79,7 @@ public class SQLServer2012DialectTestCase extends BaseUnitTestCase {
); );
} }
private Limit toRowSelection(int firstRow, int maxRows) { private Limit toRowSelection(Integer firstRow, Integer maxRows) {
final Limit selection = new Limit(); final Limit selection = new Limit();
selection.setFirstRow( firstRow ); selection.setFirstRow( firstRow );
selection.setMaxRows( maxRows ); selection.setMaxRows( maxRows );