diff --git a/src/main/java/org/apache/ibatis/jdbc/AbstractSQL.java b/src/main/java/org/apache/ibatis/jdbc/AbstractSQL.java index 87c2e5bacf3..e1d9ce1617b 100644 --- a/src/main/java/org/apache/ibatis/jdbc/AbstractSQL.java +++ b/src/main/java/org/apache/ibatis/jdbc/AbstractSQL.java @@ -270,10 +270,12 @@ public T ORDER_BY(String... columns) { * * @param variable a limit variable string * @return a self instance + * @see #OFFSET(String) * @since 3.5.2 */ public T LIMIT(String variable) { sql().limit = variable; + sql().limitingRowsStrategy = SQLStatement.LimitingRowsStrategy.OFFSET_LIMIT; return getSelf(); } @@ -282,11 +284,11 @@ public T LIMIT(String variable) { * * @param value an offset value * @return a self instance + * @see #OFFSET(long) * @since 3.5.2 */ public T LIMIT(int value) { - sql().limit = String.valueOf(value); - return getSelf(); + return LIMIT(String.valueOf(value)); } /** @@ -294,10 +296,12 @@ public T LIMIT(int value) { * * @param variable a offset variable string * @return a self instance + * @see #LIMIT(String) * @since 3.5.2 */ public T OFFSET(String variable) { sql().offset = variable; + sql().limitingRowsStrategy = SQLStatement.LimitingRowsStrategy.OFFSET_LIMIT; return getSelf(); } @@ -306,14 +310,66 @@ public T OFFSET(String variable) { * * @param value an offset value * @return a self instance + * @see #LIMIT(int) * @since 3.5.2 */ public T OFFSET(long value) { - sql().offset = String.valueOf(value); + return OFFSET(String.valueOf(value)); + } + + /** + * Set the fetch first rows variable string(e.g. {@code "#{fetchFirstRows}"}). + * + * @param variable a fetch first rows variable string + * @return a self instance + * @see #OFFSET_ROWS(String) + * @since 3.5.2 + */ + public T FETCH_FIRST_ROWS_ONLY(String variable) { + sql().limit = variable; + sql().limitingRowsStrategy = SQLStatement.LimitingRowsStrategy.ISO; + return getSelf(); + } + + /** + * Set the fetch first rows value. + * + * @param value a fetch first rows value + * @return a self instance + * @see #OFFSET_ROWS(long) + * @since 3.5.2 + */ + public T FETCH_FIRST_ROWS_ONLY(int value) { + return FETCH_FIRST_ROWS_ONLY(String.valueOf(value)); + } + + /** + * Set the offset rows variable string(e.g. {@code "#{offset}"}). + * + * @param variable a offset rows variable string + * @return a self instance + * @see #FETCH_FIRST_ROWS_ONLY(String) + * @since 3.5.2 + */ + public T OFFSET_ROWS(String variable) { + sql().offset = variable; + sql().limitingRowsStrategy = SQLStatement.LimitingRowsStrategy.ISO; return getSelf(); } /** + * Set the offset rows value. + * + * @param value an offset rows value + * @return a self instance + * @see #FETCH_FIRST_ROWS_ONLY(int) + * @since 3.5.2 + */ + public T OFFSET_ROWS(long value) { + return OFFSET_ROWS(String.valueOf(value)); + } + + /* * used to add a new inserted row while do multi-row insert. * * @since 3.5.2 @@ -372,6 +428,40 @@ public enum StatementType { DELETE, INSERT, SELECT, UPDATE } + private enum LimitingRowsStrategy { + NOP { + @Override + protected void appendClause(SafeAppendable builder, String offset, String limit) { + // NOP + } + }, + ISO { + @Override + protected void appendClause(SafeAppendable builder, String offset, String limit) { + if (offset != null) { + builder.append(" OFFSET ").append(offset).append(" ROWS"); + } + if (limit != null) { + builder.append(" FETCH FIRST ").append(limit).append(" ROWS ONLY"); + } + } + }, + OFFSET_LIMIT { + @Override + protected void appendClause(SafeAppendable builder, String offset, String limit) { + if (limit != null) { + builder.append(" LIMIT ").append(limit); + } + if (offset != null) { + builder.append(" OFFSET ").append(offset); + } + } + }; + + protected abstract void appendClause(SafeAppendable builder, String offset, String limit); + + } + StatementType statementType; List sets = new ArrayList<>(); List select = new ArrayList<>(); @@ -391,6 +481,7 @@ public enum StatementType { boolean distinct; String offset; String limit; + LimitingRowsStrategy limitingRowsStrategy = LimitingRowsStrategy.NOP; public SQLStatement() { // Prevent Synthetic Access @@ -432,12 +523,7 @@ private String selectSQL(SafeAppendable builder) { sqlClause(builder, "GROUP BY", groupBy, "", "", ", "); sqlClause(builder, "HAVING", having, "(", ")", " AND "); sqlClause(builder, "ORDER BY", orderBy, "", "", ", "); - if (limit != null) { - builder.append(" LIMIT ").append(limit); - } - if (offset != null) { - builder.append(" OFFSET ").append(offset); - } + limitingRowsStrategy.appendClause(builder, offset, limit); return builder.toString(); } @@ -461,9 +547,7 @@ private String insertSQL(SafeAppendable builder) { private String deleteSQL(SafeAppendable builder) { sqlClause(builder, "DELETE FROM", tables, "", "", ""); sqlClause(builder, "WHERE", where, "(", ")", " AND "); - if (limit != null) { - builder.append(" LIMIT ").append(limit); - } + limitingRowsStrategy.appendClause(builder, null, limit); return builder.toString(); } @@ -472,9 +556,7 @@ private String updateSQL(SafeAppendable builder) { joins(builder); sqlClause(builder, "SET", sets, "", "", ", "); sqlClause(builder, "WHERE", where, "(", ")", " AND "); - if (limit != null) { - builder.append(" LIMIT ").append(limit); - } + limitingRowsStrategy.appendClause(builder, null, limit); return builder.toString(); } diff --git a/src/site/es/xdoc/statement-builders.xml b/src/site/es/xdoc/statement-builders.xml index 01ce4351bdd..c98bbba9b34 100644 --- a/src/site/es/xdoc/statement-builders.xml +++ b/src/site/es/xdoc/statement-builders.xml @@ -297,7 +297,8 @@ public String updatePersonSql() { Appends a LIMIT clause. - This method valid when use together with SELECT(), UPDATE() and DELETE(). (Available since 3.5.2) + This method valid when use together with SELECT(), UPDATE() and DELETE(). + And this method is designed to use together with OFFSET() when use SELECT(). (Available since 3.5.2) @@ -313,7 +314,42 @@ public String updatePersonSql() { Appends a OFFSET clause. - This method valid when use together with SELECT(). (Available since 3.5.2) + This method valid when use together with SELECT(). + And this method is designed to use together with LIMIT(). (Available since 3.5.2) + + + + + + + + Appends a OFFSET n ROWS clause. + This method valid when use together with SELECT(). + And this method is designed to use together with FETCH_FIRST_ROWS_ONLY(). (Available since 3.5.2) + + + + + + + + Appends a FETCH FIRST n ROWS ONLY clause. + This method valid when use together with SELECT(). + And this method is designed to use together with OFFSET_ROWS(). (Available since 3.5.2) @@ -378,10 +414,10 @@ public String updatePersonSql() {

NOTE - It is important to note that SQL class writes LIMIT and OFFSET clauses into the generated statement as is. - In other words, the library does not attempt to normalize those values for databases that don’t support LIMIT and OFFSET directly. - Therefore, it is very important for users to understand whether or not the target database supports LIMIT and OFFSET. - If the target database does not support LIMIT and OFFSET, then it is likely that using this support will create SQL that has runtime errors. + It is important to note that SQL class writes LIMIT, OFFSET, OFFSET n ROWS and FETCH FIRST n ROWS ONLY clauses into the generated statement as is. + In other words, the library does not attempt to normalize those values for databases that don’t support these clauses directly. + Therefore, it is very important for users to understand whether or not the target database supports these clauses. + If the target database does not support these clauses, then it is likely that using this support will create SQL that has runtime errors.

Since version 3.4.2, you can use variable-length arguments as follows:

diff --git a/src/site/ja/xdoc/statement-builders.xml b/src/site/ja/xdoc/statement-builders.xml index 2da6b32ce0e..bcf8ea39b1c 100644 --- a/src/site/ja/xdoc/statement-builders.xml +++ b/src/site/ja/xdoc/statement-builders.xml @@ -314,7 +314,8 @@ public String updatePersonSql() { LIMIT 句を追加します。 - このメソッドは SELECT(), UPDATE(), DELETE() と一緒に使うと有効になります。 (3.5.2以降で利用可能) + このメソッドは SELECT(), UPDATE(), DELETE() と一緒に使うと有効になり、 + SELECT()使用時は、OFFSET()と一緒に使うように設計されています。 (3.5.2以降で利用可能) @@ -330,7 +331,42 @@ public String updatePersonSql() { OFFSET 句を追加します。 - このメソッドは SELECT() と一緒に使うと有効になります。(3.5.2以降で利用可能) + このメソッドは SELECT() と一緒に使うと有効になり、 + LIMIT()と一緒に使うように設計されています。(3.5.2以降で利用可能) + + + + + + + + OFFSET n ROWS 句を追加します。 + このメソッドは SELECT() と一緒に使うと有効になり、 + FETCH_FIRST_ROWS_ONLY()と一緒に使うように設計されています。 (3.5.2以降で利用可能) + + + + + + + + FETCH FIRST n ROWS ONLY 句を追加します。 + このメソッドは SELECT() と一緒に使うと有効になり、 + OFFSET_ROWS()と一緒に使うように設計されています。 (3.5.2以降で利用可能) @@ -397,12 +433,10 @@ public String updatePersonSql() {

NOTE - LIMITOFFSET 句は生成されたステートメントにそのまま書き込むという点に注意することが重要です。 - 言い換えると、LIMITOFFSET 句をサポートしていないデータベースに対して、 - そのデータベースで解釈可能な表現へ変換することはしません。 - そのため、利用するデータベースがLIMITOFFSET 句をサポートしているか否かを把握しておくことが重要になります。 - もし、利用するデータベースがLIMITOFFSET 句をサポートしていない場合は、 - SQL実行時にエラーになります。 + LIMITOFFSETOFFSET n ROWSFETCH FIRST n ROWS ONLY 句は生成されたステートメントにそのまま書き込むという点に注意することが重要です。 + 言い換えると、これらの句をサポートしていないデータベースに対して、そのデータベースで解釈可能な表現へ変換することはしません。 + そのため、利用するデータベースがこれらの句をサポートしているか否かを事前に把握しておくことが重要になります。 + もし、利用するデータベースがこれらの句をサポートしていない場合は、SQL実行時にエラーになります。

バージョン3.4.2以降では、次のように可変長引数を使うことができます。

diff --git a/src/site/ko/xdoc/statement-builders.xml b/src/site/ko/xdoc/statement-builders.xml index daf92b47288..639a27e497b 100644 --- a/src/site/ko/xdoc/statement-builders.xml +++ b/src/site/ko/xdoc/statement-builders.xml @@ -338,7 +338,8 @@ public String updatePersonSql() { Appends a LIMIT clause. - This method valid when use together with SELECT(), UPDATE() and DELETE(). (Available since 3.5.2) + This method valid when use together with SELECT(), UPDATE() and DELETE(). + And this method is designed to use together with OFFSET() when use SELECT(). (Available since 3.5.2) @@ -354,7 +355,42 @@ public String updatePersonSql() { Appends a OFFSET clause. - This method valid when use together with SELECT(). (Available since 3.5.2) + This method valid when use together with SELECT(). + And this method is designed to use together with LIMIT(). (Available since 3.5.2) + + + + + + + + Appends a OFFSET n ROWS clause. + This method valid when use together with SELECT(). + And this method is designed to use together with FETCH_FIRST_ROWS_ONLY(). (Available since 3.5.2) + + + + + + + + Appends a FETCH FIRST n ROWS ONLY clause. + This method valid when use together with SELECT(). + And this method is designed to use together with OFFSET_ROWS(). (Available since 3.5.2) @@ -425,10 +461,10 @@ public String updatePersonSql() {

NOTE - It is important to note that SQL class writes LIMIT and OFFSET clauses into the generated statement as is. - In other words, the library does not attempt to normalize those values for databases that don’t support LIMIT and OFFSET directly. - Therefore, it is very important for users to understand whether or not the target database supports LIMIT and OFFSET. - If the target database does not support LIMIT and OFFSET, then it is likely that using this support will create SQL that has runtime errors. + It is important to note that SQL class writes LIMIT, OFFSET, OFFSET n ROWS and FETCH FIRST n ROWS ONLY clauses into the generated statement as is. + In other words, the library does not attempt to normalize those values for databases that don’t support these clauses directly. + Therefore, it is very important for users to understand whether or not the target database supports these clauses. + If the target database does not support these clauses, then it is likely that using this support will create SQL that has runtime errors.

3.4.2 버전부터, variable-length 매개변수를 아래와 같이 사용할 수 있습니다.

diff --git a/src/site/xdoc/statement-builders.xml b/src/site/xdoc/statement-builders.xml index 88d5dda8e24..9304fce4ed3 100644 --- a/src/site/xdoc/statement-builders.xml +++ b/src/site/xdoc/statement-builders.xml @@ -365,7 +365,8 @@ public String updatePersonSql() { Appends a LIMIT clause. - This method valid when use together with SELECT(), UPDATE() and DELETE(). (Available since 3.5.2) + This method valid when use together with SELECT(), UPDATE() and DELETE(). + And this method is designed to use together with OFFSET() when use SELECT(). (Available since 3.5.2) @@ -381,7 +382,42 @@ public String updatePersonSql() { Appends a OFFSET clause. - This method valid when use together with SELECT(). (Available since 3.5.2) + This method valid when use together with SELECT(). + And this method is designed to use together with LIMIT(). (Available since 3.5.2) + + + + + + + + Appends a OFFSET n ROWS clause. + This method valid when use together with SELECT(). + And this method is designed to use together with FETCH_FIRST_ROWS_ONLY(). (Available since 3.5.2) + + + + + + + + Appends a FETCH FIRST n ROWS ONLY clause. + This method valid when use together with SELECT(). + And this method is designed to use together with OFFSET_ROWS(). (Available since 3.5.2) @@ -454,10 +490,10 @@ public String updatePersonSql() {

NOTE - It is important to note that SQL class writes LIMIT and OFFSET clauses into the generated statement as is. - In other words, the library does not attempt to normalize those values for databases that don’t support LIMIT and OFFSET directly. - Therefore, it is very important for users to understand whether or not the target database supports LIMIT and OFFSET. - If the target database does not support LIMIT and OFFSET, then it is likely that using this support will create SQL that has runtime errors. + It is important to note that SQL class writes LIMIT, OFFSET, OFFSET n ROWS and FETCH FIRST n ROWS ONLY clauses into the generated statement as is. + In other words, the library does not attempt to normalize those values for databases that don’t support these clauses directly. + Therefore, it is very important for users to understand whether or not the target database supports these clauses. + If the target database does not support these clauses, then it is likely that using this support will create SQL that has runtime errors.

Since version 3.4.2, you can use variable-length arguments as follows:

diff --git a/src/site/zh/xdoc/statement-builders.xml b/src/site/zh/xdoc/statement-builders.xml index 1a0c7c4754f..d961c5393cb 100644 --- a/src/site/zh/xdoc/statement-builders.xml +++ b/src/site/zh/xdoc/statement-builders.xml @@ -344,7 +344,8 @@ public String updatePersonSql() { Appends a LIMIT clause. - This method valid when use together with SELECT(), UPDATE() and DELETE(). (Available since 3.5.2) + This method valid when use together with SELECT(), UPDATE() and DELETE(). + And this method is designed to use together with OFFSET() when use SELECT(). (Available since 3.5.2) @@ -360,7 +361,42 @@ public String updatePersonSql() { Appends a OFFSET clause. - This method valid when use together with SELECT(). (Available since 3.5.2) + This method valid when use together with SELECT(). + And this method is designed to use together with LIMIT(). (Available since 3.5.2) + + + + + + + + Appends a OFFSET n ROWS clause. + This method valid when use together with SELECT(). + And this method is designed to use together with FETCH_FIRST_ROWS_ONLY(). (Available since 3.5.2) + + + + + + + + Appends a FETCH FIRST n ROWS ONLY clause. + This method valid when use together with SELECT(). + And this method is designed to use together with OFFSET_ROWS(). (Available since 3.5.2) @@ -427,10 +463,10 @@ public String updatePersonSql() {

NOTE - It is important to note that SQL class writes LIMIT and OFFSET clauses into the generated statement as is. - In other words, the library does not attempt to normalize those values for databases that don’t support LIMIT and OFFSET directly. - Therefore, it is very important for users to understand whether or not the target database supports LIMIT and OFFSET. - If the target database does not support LIMIT and OFFSET, then it is likely that using this support will create SQL that has runtime errors. + It is important to note that SQL class writes LIMIT, OFFSET, OFFSET n ROWS and FETCH FIRST n ROWS ONLY clauses into the generated statement as is. + In other words, the library does not attempt to normalize those values for databases that don’t support these clauses directly. + Therefore, it is very important for users to understand whether or not the target database supports these clauses. + If the target database does not support these clauses, then it is likely that using this support will create SQL that has runtime errors.

Since version 3.4.2, you can use variable-length arguments as follows:

diff --git a/src/test/java/org/apache/ibatis/jdbc/SQLTest.java b/src/test/java/org/apache/ibatis/jdbc/SQLTest.java index 878b79e3131..24756573a44 100644 --- a/src/test/java/org/apache/ibatis/jdbc/SQLTest.java +++ b/src/test/java/org/apache/ibatis/jdbc/SQLTest.java @@ -347,6 +347,33 @@ void deleteUsingLimit() { assertEquals("DELETE FROM test\nWHERE (status = #{status}) LIMIT 20", sql); } + @Test + void selectUsingFetchFirstRowsOnlyVariableName() { + final String sql = new SQL() {{ + SELECT("*").FROM("test").ORDER_BY("id").FETCH_FIRST_ROWS_ONLY("#{fetchFirstRows}"); + }}.toString(); + + assertEquals("SELECT *\nFROM test\nORDER BY id FETCH FIRST #{fetchFirstRows} ROWS ONLY", sql); + } + + @Test + void selectUsingOffsetRowsVariableName() { + final String sql = new SQL() {{ + SELECT("*").FROM("test").ORDER_BY("id").OFFSET_ROWS("#{offsetRows}"); + }}.toString(); + + assertEquals("SELECT *\nFROM test\nORDER BY id OFFSET #{offsetRows} ROWS", sql); + } + + @Test + void selectUsingOffsetRowsAndFetchFirstRowsOnly() { + final String sql = new SQL() {{ + SELECT("*").FROM("test").ORDER_BY("id").OFFSET_ROWS(100).FETCH_FIRST_ROWS_ONLY(20); + }}.toString(); + + assertEquals("SELECT *\nFROM test\nORDER BY id OFFSET 100 ROWS FETCH FIRST 20 ROWS ONLY", sql); + } + @Test void supportBatchInsert(){ final String sql = new SQL(){{ diff --git a/src/test/java/org/apache/ibatis/submitted/sql/CreateDB-hsqldb.sql b/src/test/java/org/apache/ibatis/submitted/sql/CreateDB-hsqldb.sql new file mode 100644 index 00000000000..d6304d9d167 --- /dev/null +++ b/src/test/java/org/apache/ibatis/submitted/sql/CreateDB-hsqldb.sql @@ -0,0 +1,26 @@ +-- +-- Copyright 2009-2019 the original author or authors. +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- + +DROP TABLE IF EXISTS users; + +CREATE TABLE users ( + user_id identity PRIMARY KEY, + name character varying(30) +); + +INSERT INTO users (name) values ('Jimmy'); +INSERT INTO users (name) values ('Iwao'); +INSERT INTO users (name) values ('Kazuki'); diff --git a/src/test/java/org/apache/ibatis/submitted/sql/CreateDB.sql b/src/test/java/org/apache/ibatis/submitted/sql/CreateDB.sql new file mode 100644 index 00000000000..856804e4140 --- /dev/null +++ b/src/test/java/org/apache/ibatis/submitted/sql/CreateDB.sql @@ -0,0 +1,28 @@ +-- +-- Copyright 2009-2019 the original author or authors. +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- + +DROP SCHEMA IF EXISTS mbtest; + +CREATE SCHEMA mbtest; + +CREATE TABLE mbtest.users ( + user_id serial PRIMARY KEY, + name character varying(30) +); + +INSERT INTO mbtest.users (name) values ('Jimmy'); +INSERT INTO mbtest.users (name) values ('Iwao'); +INSERT INTO mbtest.users (name) values ('Kazuki'); diff --git a/src/test/java/org/apache/ibatis/submitted/sql/HsqldbSQLTest.java b/src/test/java/org/apache/ibatis/submitted/sql/HsqldbSQLTest.java new file mode 100644 index 00000000000..a257d6796e8 --- /dev/null +++ b/src/test/java/org/apache/ibatis/submitted/sql/HsqldbSQLTest.java @@ -0,0 +1,79 @@ +/** + * Copyright 2009-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ibatis.submitted.sql; + +import java.util.List; +import java.util.Properties; + +import org.apache.ibatis.BaseDataTest; +import org.apache.ibatis.datasource.unpooled.UnpooledDataSource; +import org.apache.ibatis.mapping.Environment; +import org.apache.ibatis.session.Configuration; +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.session.SqlSessionFactoryBuilder; +import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class HsqldbSQLTest { + + private static SqlSessionFactory sqlSessionFactory; + + @BeforeAll + static void setUp() throws Exception { + Configuration configuration = new Configuration(); + Environment environment = new Environment("development", new JdbcTransactionFactory(), + new UnpooledDataSource("org.hsqldb.jdbcDriver", "jdbc:hsqldb:mem:HsqldbSQLTest", "sa", "")); + configuration.setEnvironment(environment); + configuration.setUseGeneratedKeys(true); + configuration.addMapper(Mapper.class); + Properties properties = new Properties(); + properties.setProperty("schema", ""); + configuration.setVariables(properties); + sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration); + + BaseDataTest.runScript(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), + "org/apache/ibatis/submitted/sql/CreateDB-hsqldb.sql"); + } + + @Test + void testFetchFirst() { + try (SqlSession sqlSession = sqlSessionFactory.openSession()) { + Mapper mapper = sqlSession.getMapper(Mapper.class); + { + List users = mapper.findAll(0, 2); + assertEquals(2, users.size()); + assertEquals("Jimmy", users.get(0).getName()); + assertEquals("Iwao", users.get(1).getName()); + } + { + List users = mapper.findAll(1, 2); + assertEquals(2, users.size()); + assertEquals("Iwao", users.get(0).getName()); + assertEquals("Kazuki", users.get(1).getName()); + } + { + List users = mapper.findAll(2, 2); + assertEquals(1, users.size()); + assertEquals("Kazuki", users.get(0).getName()); + } + } + } + +} diff --git a/src/test/java/org/apache/ibatis/submitted/sql/Mapper.java b/src/test/java/org/apache/ibatis/submitted/sql/Mapper.java new file mode 100644 index 00000000000..c491e768ea3 --- /dev/null +++ b/src/test/java/org/apache/ibatis/submitted/sql/Mapper.java @@ -0,0 +1,42 @@ +/** + * Copyright 2009-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ibatis.submitted.sql; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.SelectProvider; +import org.apache.ibatis.builder.annotation.ProviderMethodResolver; +import org.apache.ibatis.jdbc.SQL; + +public interface Mapper { + + @SelectProvider(type = SqlProvider.class) + List findAll(@Param("offset") long offset, @Param("limit") int limit); + + class SqlProvider implements ProviderMethodResolver { + public String findAll() { + return new SQL() + .SELECT("user_id", "name") + .FROM("${schema}users") + .ORDER_BY("user_id") + .OFFSET_ROWS("#{offset}") + .FETCH_FIRST_ROWS_ONLY("#{limit}") + .toString(); + } + } + +} diff --git a/src/test/java/org/apache/ibatis/submitted/sql/PostgresSQLTest.java b/src/test/java/org/apache/ibatis/submitted/sql/PostgresSQLTest.java new file mode 100644 index 00000000000..d0445b0e9bd --- /dev/null +++ b/src/test/java/org/apache/ibatis/submitted/sql/PostgresSQLTest.java @@ -0,0 +1,81 @@ +/** + * Copyright 2009-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ibatis.submitted.sql; + +import java.util.List; +import java.util.Properties; + +import org.apache.ibatis.BaseDataTest; +import org.apache.ibatis.mapping.Environment; +import org.apache.ibatis.session.Configuration; +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.session.SqlSessionFactoryBuilder; +import org.apache.ibatis.testcontainers.PgContainer; +import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@Tag("TestcontainersTests") +class PostgresSQLTest { + + private static SqlSessionFactory sqlSessionFactory; + + @BeforeAll + static void setUp() throws Exception { + Configuration configuration = new Configuration(); + Environment environment = new Environment("development", new JdbcTransactionFactory(), + PgContainer.getUnpooledDataSource()); + configuration.setEnvironment(environment); + configuration.setUseGeneratedKeys(true); + configuration.addMapper(Mapper.class); + Properties properties = new Properties(); + properties.setProperty("schema", "mbtest."); + configuration.setVariables(properties); + sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration); + + BaseDataTest.runScript(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), + "org/apache/ibatis/submitted/sql/CreateDB.sql"); + } + + @Test + void testFetchFirst() { + try (SqlSession sqlSession = sqlSessionFactory.openSession()) { + Mapper mapper = sqlSession.getMapper(Mapper.class); + { + List users = mapper.findAll(0, 2); + assertEquals(2, users.size()); + assertEquals("Jimmy", users.get(0).getName()); + assertEquals("Iwao", users.get(1).getName()); + } + { + List users = mapper.findAll(1, 2); + assertEquals(2, users.size()); + assertEquals("Iwao", users.get(0).getName()); + assertEquals("Kazuki", users.get(1).getName()); + } + { + List users = mapper.findAll(2, 2); + assertEquals(1, users.size()); + assertEquals("Kazuki", users.get(0).getName()); + } + } + } + +} diff --git a/src/test/java/org/apache/ibatis/submitted/sql/User.java b/src/test/java/org/apache/ibatis/submitted/sql/User.java new file mode 100644 index 00000000000..7a574ae2576 --- /dev/null +++ b/src/test/java/org/apache/ibatis/submitted/sql/User.java @@ -0,0 +1,40 @@ +/** + * Copyright 2009-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ibatis.submitted.sql; + +public class User { + + private Integer userId; + + private String name; + + public Integer getUserId() { + return userId; + } + + public void setUserId(Integer userId) { + this.userId = userId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +}