Skip to content

Commit 21bda4d

Browse files
authored
Merge pull request #1582 from kazuki43zoo/support-fetch-first
Support FETCH FIRST on SQL class
2 parents 905133e + 8545933 commit 21bda4d

File tree

13 files changed

+630
-47
lines changed

13 files changed

+630
-47
lines changed

src/main/java/org/apache/ibatis/jdbc/AbstractSQL.java

Lines changed: 97 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -270,10 +270,12 @@ public T ORDER_BY(String... columns) {
270270
*
271271
* @param variable a limit variable string
272272
* @return a self instance
273+
* @see #OFFSET(String)
273274
* @since 3.5.2
274275
*/
275276
public T LIMIT(String variable) {
276277
sql().limit = variable;
278+
sql().limitingRowsStrategy = SQLStatement.LimitingRowsStrategy.OFFSET_LIMIT;
277279
return getSelf();
278280
}
279281

@@ -282,22 +284,24 @@ public T LIMIT(String variable) {
282284
*
283285
* @param value an offset value
284286
* @return a self instance
287+
* @see #OFFSET(long)
285288
* @since 3.5.2
286289
*/
287290
public T LIMIT(int value) {
288-
sql().limit = String.valueOf(value);
289-
return getSelf();
291+
return LIMIT(String.valueOf(value));
290292
}
291293

292294
/**
293295
* Set the offset variable string(e.g. {@code "#{offset}"}).
294296
*
295297
* @param variable a offset variable string
296298
* @return a self instance
299+
* @see #LIMIT(String)
297300
* @since 3.5.2
298301
*/
299302
public T OFFSET(String variable) {
300303
sql().offset = variable;
304+
sql().limitingRowsStrategy = SQLStatement.LimitingRowsStrategy.OFFSET_LIMIT;
301305
return getSelf();
302306
}
303307

@@ -306,14 +310,66 @@ public T OFFSET(String variable) {
306310
*
307311
* @param value an offset value
308312
* @return a self instance
313+
* @see #LIMIT(int)
309314
* @since 3.5.2
310315
*/
311316
public T OFFSET(long value) {
312-
sql().offset = String.valueOf(value);
317+
return OFFSET(String.valueOf(value));
318+
}
319+
320+
/**
321+
* Set the fetch first rows variable string(e.g. {@code "#{fetchFirstRows}"}).
322+
*
323+
* @param variable a fetch first rows variable string
324+
* @return a self instance
325+
* @see #OFFSET_ROWS(String)
326+
* @since 3.5.2
327+
*/
328+
public T FETCH_FIRST_ROWS_ONLY(String variable) {
329+
sql().limit = variable;
330+
sql().limitingRowsStrategy = SQLStatement.LimitingRowsStrategy.ISO;
331+
return getSelf();
332+
}
333+
334+
/**
335+
* Set the fetch first rows value.
336+
*
337+
* @param value a fetch first rows value
338+
* @return a self instance
339+
* @see #OFFSET_ROWS(long)
340+
* @since 3.5.2
341+
*/
342+
public T FETCH_FIRST_ROWS_ONLY(int value) {
343+
return FETCH_FIRST_ROWS_ONLY(String.valueOf(value));
344+
}
345+
346+
/**
347+
* Set the offset rows variable string(e.g. {@code "#{offset}"}).
348+
*
349+
* @param variable a offset rows variable string
350+
* @return a self instance
351+
* @see #FETCH_FIRST_ROWS_ONLY(String)
352+
* @since 3.5.2
353+
*/
354+
public T OFFSET_ROWS(String variable) {
355+
sql().offset = variable;
356+
sql().limitingRowsStrategy = SQLStatement.LimitingRowsStrategy.ISO;
313357
return getSelf();
314358
}
315359

316360
/**
361+
* Set the offset rows value.
362+
*
363+
* @param value an offset rows value
364+
* @return a self instance
365+
* @see #FETCH_FIRST_ROWS_ONLY(int)
366+
* @since 3.5.2
367+
*/
368+
public T OFFSET_ROWS(long value) {
369+
return OFFSET_ROWS(String.valueOf(value));
370+
}
371+
372+
/*
317373
* used to add a new inserted row while do multi-row insert.
318374
*
319375
* @since 3.5.2
@@ -372,6 +428,40 @@ public enum StatementType {
372428
DELETE, INSERT, SELECT, UPDATE
373429
}
374430

431+
private enum LimitingRowsStrategy {
432+
NOP {
433+
@Override
434+
protected void appendClause(SafeAppendable builder, String offset, String limit) {
435+
// NOP
436+
}
437+
},
438+
ISO {
439+
@Override
440+
protected void appendClause(SafeAppendable builder, String offset, String limit) {
441+
if (offset != null) {
442+
builder.append(" OFFSET ").append(offset).append(" ROWS");
443+
}
444+
if (limit != null) {
445+
builder.append(" FETCH FIRST ").append(limit).append(" ROWS ONLY");
446+
}
447+
}
448+
},
449+
OFFSET_LIMIT {
450+
@Override
451+
protected void appendClause(SafeAppendable builder, String offset, String limit) {
452+
if (limit != null) {
453+
builder.append(" LIMIT ").append(limit);
454+
}
455+
if (offset != null) {
456+
builder.append(" OFFSET ").append(offset);
457+
}
458+
}
459+
};
460+
461+
protected abstract void appendClause(SafeAppendable builder, String offset, String limit);
462+
463+
}
464+
375465
StatementType statementType;
376466
List<String> sets = new ArrayList<>();
377467
List<String> select = new ArrayList<>();
@@ -391,6 +481,7 @@ public enum StatementType {
391481
boolean distinct;
392482
String offset;
393483
String limit;
484+
LimitingRowsStrategy limitingRowsStrategy = LimitingRowsStrategy.NOP;
394485

395486
public SQLStatement() {
396487
// Prevent Synthetic Access
@@ -432,12 +523,7 @@ private String selectSQL(SafeAppendable builder) {
432523
sqlClause(builder, "GROUP BY", groupBy, "", "", ", ");
433524
sqlClause(builder, "HAVING", having, "(", ")", " AND ");
434525
sqlClause(builder, "ORDER BY", orderBy, "", "", ", ");
435-
if (limit != null) {
436-
builder.append(" LIMIT ").append(limit);
437-
}
438-
if (offset != null) {
439-
builder.append(" OFFSET ").append(offset);
440-
}
526+
limitingRowsStrategy.appendClause(builder, offset, limit);
441527
return builder.toString();
442528
}
443529

@@ -461,9 +547,7 @@ private String insertSQL(SafeAppendable builder) {
461547
private String deleteSQL(SafeAppendable builder) {
462548
sqlClause(builder, "DELETE FROM", tables, "", "", "");
463549
sqlClause(builder, "WHERE", where, "(", ")", " AND ");
464-
if (limit != null) {
465-
builder.append(" LIMIT ").append(limit);
466-
}
550+
limitingRowsStrategy.appendClause(builder, null, limit);
467551
return builder.toString();
468552
}
469553

@@ -472,9 +556,7 @@ private String updateSQL(SafeAppendable builder) {
472556
joins(builder);
473557
sqlClause(builder, "SET", sets, "", "", ", ");
474558
sqlClause(builder, "WHERE", where, "(", ")", " AND ");
475-
if (limit != null) {
476-
builder.append(" LIMIT ").append(limit);
477-
}
559+
limitingRowsStrategy.appendClause(builder, null, limit);
478560
return builder.toString();
479561
}
480562

src/site/es/xdoc/statement-builders.xml

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,8 @@ public String updatePersonSql() {
297297
</td>
298298
<td>
299299
Appends a <code>LIMIT</code> clause.
300-
This method valid when use together with SELECT(), UPDATE() and DELETE(). (Available since 3.5.2)
300+
This method valid when use together with SELECT(), UPDATE() and DELETE().
301+
And this method is designed to use together with OFFSET() when use SELECT(). (Available since 3.5.2)
301302
</td>
302303
</tr>
303304
<tr>
@@ -313,7 +314,42 @@ public String updatePersonSql() {
313314
</td>
314315
<td>
315316
Appends a <code>OFFSET</code> clause.
316-
This method valid when use together with SELECT(). (Available since 3.5.2)
317+
This method valid when use together with SELECT().
318+
And this method is designed to use together with LIMIT(). (Available since 3.5.2)
319+
</td>
320+
</tr>
321+
<tr>
322+
<td>
323+
<ul>
324+
<li>
325+
<code>OFFSET_ROWS(String)</code>
326+
</li>
327+
<li>
328+
<code>OFFSET_ROWS(long)</code>
329+
</li>
330+
</ul>
331+
</td>
332+
<td>
333+
Appends a <code>OFFSET n ROWS</code> clause.
334+
This method valid when use together with SELECT().
335+
And this method is designed to use together with FETCH_FIRST_ROWS_ONLY(). (Available since 3.5.2)
336+
</td>
337+
</tr>
338+
<tr>
339+
<td>
340+
<ul>
341+
<li>
342+
<code>FETCH_FIRST_ROWS_ONLY(String)</code>
343+
</li>
344+
<li>
345+
<code>FETCH_FIRST_ROWS_ONLY(int)</code>
346+
</li>
347+
</ul>
348+
</td>
349+
<td>
350+
Appends a <code>FETCH FIRST n ROWS ONLY</code> clause.
351+
This method valid when use together with SELECT().
352+
And this method is designed to use together with OFFSET_ROWS(). (Available since 3.5.2)
317353
</td>
318354
</tr>
319355
<tr>
@@ -378,10 +414,10 @@ public String updatePersonSql() {
378414

379415
<p>
380416
<span class="label important">NOTE</span>
381-
It is important to note that SQL class writes <code>LIMIT</code> and <code>OFFSET</code> clauses into the generated statement as is.
382-
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.
383-
Therefore, it is very important for users to understand whether or not the target database supports <code>LIMIT</code> and <code>OFFSET</code>.
384-
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.
417+
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.
418+
In other words, the library does not attempt to normalize those values for databases that don’t support these clauses directly.
419+
Therefore, it is very important for users to understand whether or not the target database supports these clauses.
420+
If the target database does not support these clauses, then it is likely that using this support will create SQL that has runtime errors.
385421
</p>
386422

387423
<p>Since version 3.4.2, you can use variable-length arguments as follows:</p>

src/site/ja/xdoc/statement-builders.xml

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,8 @@ public String updatePersonSql() {
314314
</td>
315315
<td>
316316
<code>LIMIT</code> 句を追加します。
317-
このメソッドは SELECT(), UPDATE(), DELETE() と一緒に使うと有効になります。 (3.5.2以降で利用可能)
317+
このメソッドは SELECT(), UPDATE(), DELETE() と一緒に使うと有効になり、
318+
SELECT()使用時は、OFFSET()と一緒に使うように設計されています。 (3.5.2以降で利用可能)
318319
</td>
319320
</tr>
320321
<tr>
@@ -330,7 +331,42 @@ public String updatePersonSql() {
330331
</td>
331332
<td>
332333
<code>OFFSET</code> 句を追加します。
333-
このメソッドは SELECT() と一緒に使うと有効になります。(3.5.2以降で利用可能)
334+
このメソッドは SELECT() と一緒に使うと有効になり、
335+
LIMIT()と一緒に使うように設計されています。(3.5.2以降で利用可能)
336+
</td>
337+
</tr>
338+
<tr>
339+
<td>
340+
<ul>
341+
<li>
342+
<code>OFFSET_ROWS(String)</code>
343+
</li>
344+
<li>
345+
<code>OFFSET_ROWS(long)</code>
346+
</li>
347+
</ul>
348+
</td>
349+
<td>
350+
<code>OFFSET n ROWS</code> 句を追加します。
351+
このメソッドは SELECT() と一緒に使うと有効になり、
352+
FETCH_FIRST_ROWS_ONLY()と一緒に使うように設計されています。 (3.5.2以降で利用可能)
353+
</td>
354+
</tr>
355+
<tr>
356+
<td>
357+
<ul>
358+
<li>
359+
<code>FETCH_FIRST_ROWS_ONLY(String)</code>
360+
</li>
361+
<li>
362+
<code>FETCH_FIRST_ROWS_ONLY(int)</code>
363+
</li>
364+
</ul>
365+
</td>
366+
<td>
367+
<code>FETCH FIRST n ROWS ONLY</code> 句を追加します。
368+
このメソッドは SELECT() と一緒に使うと有効になり、
369+
OFFSET_ROWS()と一緒に使うように設計されています。 (3.5.2以降で利用可能)
334370
</td>
335371
</tr>
336372
<tr>
@@ -397,12 +433,10 @@ public String updatePersonSql() {
397433

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

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

0 commit comments

Comments
 (0)