Skip to content

Support FETCH FIRST on SQL builder class #1582

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 97 additions & 15 deletions src/main/java/org/apache/ibatis/jdbc/AbstractSQL.java
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand All @@ -282,22 +284,24 @@ 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));
}

/**
* Set the offset variable string(e.g. {@code "#{offset}"}).
*
* @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();
}

Expand All @@ -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
Expand Down Expand Up @@ -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<String> sets = new ArrayList<>();
List<String> select = new ArrayList<>();
Expand All @@ -391,6 +481,7 @@ public enum StatementType {
boolean distinct;
String offset;
String limit;
LimitingRowsStrategy limitingRowsStrategy = LimitingRowsStrategy.NOP;

public SQLStatement() {
// Prevent Synthetic Access
Expand Down Expand Up @@ -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();
}

Expand All @@ -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();
}

Expand All @@ -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();
}

Expand Down
48 changes: 42 additions & 6 deletions src/site/es/xdoc/statement-builders.xml
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,8 @@ public String updatePersonSql() {
</td>
<td>
Appends a <code>LIMIT</code> 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)
</td>
</tr>
<tr>
Expand All @@ -313,7 +314,42 @@ public String updatePersonSql() {
</td>
<td>
Appends a <code>OFFSET</code> 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)
</td>
</tr>
<tr>
<td>
<ul>
<li>
<code>OFFSET_ROWS(String)</code>
</li>
<li>
<code>OFFSET_ROWS(long)</code>
</li>
</ul>
</td>
<td>
Appends a <code>OFFSET n ROWS</code> 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)
</td>
</tr>
<tr>
<td>
<ul>
<li>
<code>FETCH_FIRST_ROWS_ONLY(String)</code>
</li>
<li>
<code>FETCH_FIRST_ROWS_ONLY(int)</code>
</li>
</ul>
</td>
<td>
Appends a <code>FETCH FIRST n ROWS ONLY</code> 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)
</td>
</tr>
<tr>
Expand Down Expand Up @@ -378,10 +414,10 @@ public String updatePersonSql() {

<p>
<span class="label important">NOTE</span>
It is important to note that SQL class writes <code>LIMIT</code> and <code>OFFSET</code> 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 <code>LIMIT</code> and <code>OFFSET</code> directly.
Therefore, it is very important for users to understand whether or not the target database supports <code>LIMIT</code> and <code>OFFSET</code>.
If the target database does not support <code>LIMIT</code> and <code>OFFSET</code>, then it is likely that using this support will create SQL that has runtime errors.
It is important to note that SQL class writes <code>LIMIT</code>, <code>OFFSET</code>, <code>OFFSET n ROWS</code> and <code>FETCH FIRST n ROWS ONLY</code> 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.
</p>

<p>Since version 3.4.2, you can use variable-length arguments as follows:</p>
Expand Down
50 changes: 42 additions & 8 deletions src/site/ja/xdoc/statement-builders.xml
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,8 @@ public String updatePersonSql() {
</td>
<td>
<code>LIMIT</code> 句を追加します。
このメソッドは SELECT(), UPDATE(), DELETE() と一緒に使うと有効になります。 (3.5.2以降で利用可能)
このメソッドは SELECT(), UPDATE(), DELETE() と一緒に使うと有効になり、
SELECT()使用時は、OFFSET()と一緒に使うように設計されています。 (3.5.2以降で利用可能)
</td>
</tr>
<tr>
Expand All @@ -330,7 +331,42 @@ public String updatePersonSql() {
</td>
<td>
<code>OFFSET</code> 句を追加します。
このメソッドは SELECT() と一緒に使うと有効になります。(3.5.2以降で利用可能)
このメソッドは SELECT() と一緒に使うと有効になり、
LIMIT()と一緒に使うように設計されています。(3.5.2以降で利用可能)
</td>
</tr>
<tr>
<td>
<ul>
<li>
<code>OFFSET_ROWS(String)</code>
</li>
<li>
<code>OFFSET_ROWS(long)</code>
</li>
</ul>
</td>
<td>
<code>OFFSET n ROWS</code> 句を追加します。
このメソッドは SELECT() と一緒に使うと有効になり、
FETCH_FIRST_ROWS_ONLY()と一緒に使うように設計されています。 (3.5.2以降で利用可能)
</td>
</tr>
<tr>
<td>
<ul>
<li>
<code>FETCH_FIRST_ROWS_ONLY(String)</code>
</li>
<li>
<code>FETCH_FIRST_ROWS_ONLY(int)</code>
</li>
</ul>
</td>
<td>
<code>FETCH FIRST n ROWS ONLY</code> 句を追加します。
このメソッドは SELECT() と一緒に使うと有効になり、
OFFSET_ROWS()と一緒に使うように設計されています。 (3.5.2以降で利用可能)
</td>
</tr>
<tr>
Expand Down Expand Up @@ -397,12 +433,10 @@ public String updatePersonSql() {

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

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