Skip to content

Commit db2d622

Browse files
hpoettkerfmbenhassine
authored andcommitted
Adapt H2PagingQueryProvider for H2 v2.x
Issue #4047
1 parent 4dddb10 commit db2d622

File tree

3 files changed

+129
-20
lines changed

3 files changed

+129
-20
lines changed

Diff for: spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/H2PagingQueryProvider.java

+10-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2006-2008 the original author or authors.
2+
* Copyright 2006-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -20,22 +20,23 @@
2020
* H2 implementation of a {@link org.springframework.batch.item.database.PagingQueryProvider} using database specific features.
2121
*
2222
* @author Dave Syer
23+
* @author Henning Pöttker
2324
* @since 2.1
2425
*/
2526
public class H2PagingQueryProvider extends AbstractSqlPagingQueryProvider {
2627

2728
@Override
2829
public String generateFirstPageQuery(int pageSize) {
29-
return SqlPagingQueryUtils.generateTopSqlQuery(this, false, buildTopClause(pageSize));
30+
return SqlPagingQueryUtils.generateLimitSqlQuery(this, false, buildLimitClause(pageSize));
3031
}
3132

3233
@Override
3334
public String generateRemainingPagesQuery(int pageSize) {
34-
return SqlPagingQueryUtils.generateTopSqlQuery(this, true, buildTopClause(pageSize));
35+
return SqlPagingQueryUtils.generateLimitSqlQuery(this, true, buildLimitClause(pageSize));
3536
}
3637

37-
private String buildTopClause(int pageSize) {
38-
return new StringBuilder().append("TOP ").append(pageSize).toString();
38+
private String buildLimitClause(int pageSize) {
39+
return new StringBuilder().append("FETCH NEXT ").append(pageSize).append(" ROWS ONLY").toString();
3940
}
4041

4142
@Override
@@ -44,8 +45,10 @@ public String generateJumpToItemQuery(int itemIndex, int pageSize) {
4445
int offset = (page * pageSize) - 1;
4546
offset = offset<0 ? 0 : offset;
4647

47-
String topClause = new StringBuilder().append("LIMIT ").append(offset).append(" 1").toString();
48-
return SqlPagingQueryUtils.generateTopJumpToQuery(this, topClause);
48+
String limitClause = new StringBuilder().append("OFFSET ")
49+
.append(offset).append(" ROWS FETCH NEXT 1 ROWS ONLY")
50+
.toString();
51+
return SqlPagingQueryUtils.generateLimitJumpToQuery(this, limitClause);
4952
}
5053

5154
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Copyright 2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.batch.item.database.support;
17+
18+
import java.util.Arrays;
19+
import java.util.HashMap;
20+
import java.util.List;
21+
import java.util.Map;
22+
import java.util.UUID;
23+
import java.util.stream.Collectors;
24+
25+
import javax.sql.DataSource;
26+
27+
import org.junit.Test;
28+
import org.junit.runner.RunWith;
29+
import org.junit.runners.Parameterized;
30+
import org.junit.runners.Parameterized.Parameters;
31+
32+
import org.springframework.batch.item.database.Order;
33+
import org.springframework.jdbc.core.JdbcTemplate;
34+
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
35+
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
36+
import org.springframework.transaction.PlatformTransactionManager;
37+
import org.springframework.transaction.support.TransactionTemplate;
38+
39+
import static org.junit.Assert.assertArrayEquals;
40+
import static org.junit.Assert.assertEquals;
41+
42+
/**
43+
* @author Henning Pöttker
44+
*/
45+
@RunWith(Parameterized.class)
46+
public class H2PagingQueryProviderIntegrationTests {
47+
48+
private final String compatibilityMode;
49+
50+
public H2PagingQueryProviderIntegrationTests(String compatibilityMode) {
51+
this.compatibilityMode = compatibilityMode;
52+
}
53+
54+
@Test
55+
public void testQueryProvider() {
56+
String connectionUrl = String.format("jdbc:h2:mem:%s;MODE=%s", UUID.randomUUID(), compatibilityMode);
57+
DataSource dataSource = new SimpleDriverDataSource(new org.h2.Driver(), connectionUrl, "sa", "");
58+
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
59+
PlatformTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
60+
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
61+
62+
transactionTemplate.executeWithoutResult(status -> {
63+
jdbcTemplate.execute("CREATE TABLE TEST_TABLE (ID BIGINT NOT NULL, STRING VARCHAR(16) NOT NULL)");
64+
jdbcTemplate.execute("INSERT INTO TEST_TABLE (ID, STRING) VALUES (1, 'Spring')");
65+
jdbcTemplate.execute("INSERT INTO TEST_TABLE (ID, STRING) VALUES (2, 'Batch')");
66+
jdbcTemplate.execute("INSERT INTO TEST_TABLE (ID, STRING) VALUES (3, 'Infrastructure')");
67+
68+
H2PagingQueryProvider queryProvider = new H2PagingQueryProvider();
69+
queryProvider.setSelectClause("STRING");
70+
queryProvider.setFromClause("TEST_TABLE");
71+
Map<String, Order> sortKeys = new HashMap<>();
72+
sortKeys.put("ID", Order.ASCENDING);
73+
queryProvider.setSortKeys(sortKeys);
74+
75+
List<String> firstPage = jdbcTemplate.queryForList(
76+
queryProvider.generateFirstPageQuery(2),
77+
String.class
78+
);
79+
assertArrayEquals("firstPage", new String[]{"Spring", "Batch"}, firstPage.toArray());
80+
81+
List<String> secondPage = jdbcTemplate.queryForList(
82+
queryProvider.generateRemainingPagesQuery(2),
83+
String.class,
84+
2
85+
);
86+
assertArrayEquals("secondPage", new String[]{"Infrastructure"}, secondPage.toArray());
87+
88+
Integer secondItem = jdbcTemplate.queryForObject(
89+
queryProvider.generateJumpToItemQuery(3, 2),
90+
Integer.class
91+
);
92+
assertEquals(Integer.valueOf(2), secondItem);
93+
});
94+
}
95+
96+
@Parameters
97+
public static List<Object[]> data() throws Exception {
98+
return Arrays.stream(org.h2.engine.Mode.ModeEnum.values())
99+
.map(mode -> new Object[]{mode.toString()})
100+
.collect(Collectors.toList());
101+
}
102+
}

Diff for: spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/H2PagingQueryProviderTests.java

+17-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2006-2015 the original author or authors.
2+
* Copyright 2006-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@
2323
* @author Thomas Risberg
2424
* @author Dave Syer
2525
* @author Michael Minella
26+
* @author Henning Pöttker
2627
*/
2728
public class H2PagingQueryProviderTests extends AbstractSqlPagingQueryProviderTests {
2829

@@ -33,28 +34,29 @@ public H2PagingQueryProviderTests() {
3334
@Test
3435
@Override
3536
public void testGenerateFirstPageQuery() {
36-
String sql = "SELECT TOP 100 id, name, age FROM foo WHERE bar = 1 ORDER BY id ASC";
37+
String sql = "SELECT id, name, age FROM foo WHERE bar = 1 ORDER BY id ASC FETCH NEXT 100 ROWS ONLY";
3738
String s = pagingQueryProvider.generateFirstPageQuery(pageSize);
3839
assertEquals(sql, s);
3940
}
4041

4142
@Test @Override
4243
public void testGenerateRemainingPagesQuery() {
43-
String sql = "SELECT TOP 100 id, name, age FROM foo WHERE (bar = 1) AND ((id > ?)) ORDER BY id ASC";
44+
String sql = "SELECT id, name, age FROM foo WHERE (bar = 1) AND ((id > ?)) "
45+
+ "ORDER BY id ASC FETCH NEXT 100 ROWS ONLY";
4446
String s = pagingQueryProvider.generateRemainingPagesQuery(pageSize);
4547
assertEquals(sql, s);
4648
}
4749

4850
@Test @Override
4951
public void testGenerateJumpToItemQuery() {
50-
String sql = "SELECT LIMIT 99 1 id FROM foo WHERE bar = 1 ORDER BY id ASC";
52+
String sql = "SELECT id FROM foo WHERE bar = 1 ORDER BY id ASC OFFSET 99 ROWS FETCH NEXT 1 ROWS ONLY";
5153
String s = pagingQueryProvider.generateJumpToItemQuery(145, pageSize);
5254
assertEquals(sql, s);
5355
}
5456

5557
@Test @Override
5658
public void testGenerateJumpToItemQueryForFirstPage() {
57-
String sql = "SELECT LIMIT 0 1 id FROM foo WHERE bar = 1 ORDER BY id ASC";
59+
String sql = "SELECT id FROM foo WHERE bar = 1 ORDER BY id ASC OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY";
5860
String s = pagingQueryProvider.generateJumpToItemQuery(45, pageSize);
5961
assertEquals(sql, s);
6062
}
@@ -63,7 +65,7 @@ public void testGenerateJumpToItemQueryForFirstPage() {
6365
@Test
6466
public void testGenerateFirstPageQueryWithGroupBy() {
6567
pagingQueryProvider.setGroupClause("dep");
66-
String sql = "SELECT TOP 100 id, name, age FROM foo WHERE bar = 1 GROUP BY dep ORDER BY id ASC";
68+
String sql = "SELECT id, name, age FROM foo WHERE bar = 1 GROUP BY dep ORDER BY id ASC FETCH NEXT 100 ROWS ONLY";
6769
String s = pagingQueryProvider.generateFirstPageQuery(pageSize);
6870
assertEquals(sql, s);
6971
}
@@ -72,7 +74,8 @@ public void testGenerateFirstPageQueryWithGroupBy() {
7274
@Test
7375
public void testGenerateRemainingPagesQueryWithGroupBy() {
7476
pagingQueryProvider.setGroupClause("dep");
75-
String sql = "SELECT TOP 100 id, name, age FROM foo WHERE (bar = 1) AND ((id > ?)) GROUP BY dep ORDER BY id ASC";
77+
String sql = "SELECT id, name, age FROM foo WHERE (bar = 1) AND ((id > ?)) GROUP BY dep "
78+
+ "ORDER BY id ASC FETCH NEXT 100 ROWS ONLY";
7679
String s = pagingQueryProvider.generateRemainingPagesQuery(pageSize);
7780
assertEquals(sql, s);
7881
}
@@ -81,7 +84,7 @@ public void testGenerateRemainingPagesQueryWithGroupBy() {
8184
@Test
8285
public void testGenerateJumpToItemQueryWithGroupBy() {
8386
pagingQueryProvider.setGroupClause("dep");
84-
String sql = "SELECT LIMIT 99 1 id FROM foo WHERE bar = 1 GROUP BY dep ORDER BY id ASC";
87+
String sql = "SELECT id FROM foo WHERE bar = 1 GROUP BY dep ORDER BY id ASC OFFSET 99 ROWS FETCH NEXT 1 ROWS ONLY";
8588
String s = pagingQueryProvider.generateJumpToItemQuery(145, pageSize);
8689
assertEquals(sql, s);
8790
}
@@ -90,28 +93,29 @@ public void testGenerateJumpToItemQueryWithGroupBy() {
9093
@Test
9194
public void testGenerateJumpToItemQueryForFirstPageWithGroupBy() {
9295
pagingQueryProvider.setGroupClause("dep");
93-
String sql = "SELECT LIMIT 0 1 id FROM foo WHERE bar = 1 GROUP BY dep ORDER BY id ASC";
96+
String sql = "SELECT id FROM foo WHERE bar = 1 GROUP BY dep ORDER BY id ASC OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY";
9497
String s = pagingQueryProvider.generateJumpToItemQuery(45, pageSize);
9598
assertEquals(sql, s);
9699
}
97100

98101
@Override
99102
public String getFirstPageSqlWithMultipleSortKeys() {
100-
return "SELECT TOP 100 id, name, age FROM foo WHERE bar = 1 ORDER BY name ASC, id DESC";
103+
return "SELECT id, name, age FROM foo WHERE bar = 1 ORDER BY name ASC, id DESC FETCH NEXT 100 ROWS ONLY";
101104
}
102105

103106
@Override
104107
public String getRemainingSqlWithMultipleSortKeys() {
105-
return "SELECT TOP 100 id, name, age FROM foo WHERE (bar = 1) AND ((name > ?) OR (name = ? AND id < ?)) ORDER BY name ASC, id DESC";
108+
return "SELECT id, name, age FROM foo WHERE (bar = 1) AND ((name > ?) OR (name = ? AND id < ?)) "
109+
+ "ORDER BY name ASC, id DESC FETCH NEXT 100 ROWS ONLY";
106110
}
107111

108112
@Override
109113
public String getJumpToItemQueryWithMultipleSortKeys() {
110-
return "SELECT LIMIT 99 1 name, id FROM foo WHERE bar = 1 ORDER BY name ASC, id DESC";
114+
return "SELECT name, id FROM foo WHERE bar = 1 ORDER BY name ASC, id DESC OFFSET 99 ROWS FETCH NEXT 1 ROWS ONLY";
111115
}
112116

113117
@Override
114118
public String getJumpToItemQueryForFirstPageWithMultipleSortKeys() {
115-
return "SELECT LIMIT 0 1 name, id FROM foo WHERE bar = 1 ORDER BY name ASC, id DESC";
119+
return "SELECT name, id FROM foo WHERE bar = 1 ORDER BY name ASC, id DESC OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY";
116120
}
117121
}

0 commit comments

Comments
 (0)