001package com.avaje.ebean.config.dbplatform;
002
003/**
004 * Add ROWNUM column etc around SQL query to limit results.
005 */
006public class RownumSqlLimiter implements SqlLimiter {
007
008  private final String rnum;
009
010  private final boolean useFirstRowsHint;
011
012  /**
013   * Create with default inner rownum column alias and used FIRST_ROWS hint.
014   */
015  public RownumSqlLimiter() {
016    this("rn_", true);
017  }
018
019  /**
020   * Specify the inner rownum column alias and whether to include the FIRST_ROWS
021   * hint.
022   */
023  public RownumSqlLimiter(String rnum, boolean useFirstRowsHint) {
024    this.rnum = rnum;
025    this.useFirstRowsHint = useFirstRowsHint;
026  }
027
028  public SqlLimitResponse limit(SqlLimitRequest request) {
029
030    // select *
031    // from ( select /*+ FIRST_ROWS(n) */ ROWNUM rnum, a.*
032    // from ( your_query_goes_here,
033    // with order by ) a
034    // where ROWNUM <=
035    // :MAX_ROW_TO_FETCH )
036    // where rnum >= :MIN_ROW_TO_FETCH;
037
038    String dbSql = request.getDbSql();
039    
040    StringBuilder sb = new StringBuilder(60 + dbSql.length());
041
042    int firstRow = request.getFirstRow();
043
044    int lastRow = request.getMaxRows();
045    if (lastRow > 0) {
046      lastRow = lastRow + firstRow;
047    }
048
049    sb.append("select * from ( ");
050
051    sb.append("select ");
052    if (useFirstRowsHint && request.getMaxRows() > 0) {
053      sb.append("/*+ FIRST_ROWS(").append(request.getMaxRows()).append(") */ ");
054    }
055
056    sb.append("rownum ").append(rnum).append(", a.* ");
057    sb.append(" from (");
058
059    sb.append(" select ");
060    if (request.isDistinct()) {
061      sb.append("distinct ");
062    }
063    sb.append(dbSql);
064
065    sb.append(NEW_LINE).append("  ) a ");
066    if (lastRow > 0) {
067      sb.append(" where rownum <= ").append(lastRow);
068    }
069    sb.append(" ) ");
070    if (firstRow > 0) {
071      sb.append(" where ");
072      sb.append(rnum).append(" > ").append(firstRow);
073    }
074
075    String sql = request.getDbPlatform().completeSql(sb.toString(), request.getOrmQuery());
076
077    return new SqlLimitResponse(sql, true);
078  }
079
080}