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}