001/* 002 * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package com.mybatisflex.core.dialect; 017 018import com.mybatisflex.core.query.CPI; 019import com.mybatisflex.core.query.QueryOrderBy; 020import com.mybatisflex.core.query.QueryTable; 021import com.mybatisflex.core.query.QueryWrapper; 022import com.mybatisflex.core.util.CollectionUtil; 023 024import java.util.List; 025 026import static com.mybatisflex.core.constant.SqlConsts.*; 027 028/** 029 * limit 和 offset 参数的处理器 030 */ 031public interface LimitOffsetProcessor { 032 033 /** 034 * 处理构建 limit 和 offset 035 * 036 * @param dialect 数据方言 037 * @param sql 已经构建的 sql 038 * @param queryWrapper 参数内容 039 * @param limitRows 用户传入的 limit 参数 可能为 null 040 * @param limitOffset 用户传入的 offset 参数,可能为 null 041 */ 042 StringBuilder process(IDialect dialect, StringBuilder sql, QueryWrapper queryWrapper, Long limitRows, Long limitOffset); 043 044 045 /** 046 * MySql 的处理器 047 * 适合 {@link DbType#MYSQL,DbType#MARIADB,DbType#H2,DbType#CLICK_HOUSE,DbType#XCloud} 048 */ 049 LimitOffsetProcessor MYSQL = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { 050 if (limitRows != null && limitOffset != null) { 051 sql.append(LIMIT).append(limitOffset).append(DELIMITER).append(limitRows); 052 } else if (limitRows != null) { 053 sql.append(LIMIT).append(limitRows); 054 } 055 return sql; 056 }; 057 058 /** 059 * Postgresql 的处理器 060 * 适合 {@link DbType#POSTGRE_SQL,DbType#SQLITE,DbType#H2,DbType#HSQL,DbType#KINGBASE_ES,DbType#PHOENIX} 061 * 适合 {@link DbType#SAP_HANA,DbType#IMPALA,DbType#HIGH_GO,DbType#VERTICA,DbType#REDSHIFT} 062 * 适合 {@link DbType#OPENGAUSS,DbType#TDENGINE,DbType#UXDB} 063 */ 064 LimitOffsetProcessor POSTGRESQL = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { 065 if (limitRows != null && limitOffset != null) { 066 sql.append(LIMIT).append(limitRows).append(OFFSET).append(limitOffset); 067 } else if (limitRows != null) { 068 sql.append(LIMIT).append(limitRows); 069 } 070 return sql; 071 }; 072 073 /** 074 * derby 的处理器 075 * 适合 {@link DbType#DERBY,DbType#ORACLE_12C,DbType#SQLSERVER ,DbType#POSTGRE_SQL} 076 */ 077 LimitOffsetProcessor DERBY = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { 078 if (limitRows != null && limitOffset != null) { 079 // OFFSET ** ROWS FETCH NEXT ** ROWS ONLY") 080 sql.append(OFFSET).append(limitOffset).append(ROWS_FETCH_NEXT).append(limitRows).append(ROWS_ONLY); 081 } else if (limitRows != null) { 082 sql.append(OFFSET).append(0).append(ROWS_FETCH_NEXT).append(limitRows).append(ROWS_ONLY); 083 } 084 return sql; 085 }; 086 087 /** 088 * derby 的处理器 089 * 适合 {@link DbType#DERBY,DbType#ORACLE_12C,DbType#SQLSERVER ,DbType#POSTGRE_SQL} 090 */ 091 LimitOffsetProcessor SQLSERVER = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { 092 if (limitRows != null && limitOffset != null) { 093 // OFFSET ** ROWS FETCH NEXT ** ROWS ONLY") 094 sql.append(OFFSET).append(limitOffset).append(ROWS_FETCH_NEXT).append(limitRows).append(ROWS_ONLY); 095 } else if (limitRows != null) { 096 List<QueryOrderBy> orderBys = CPI.getOrderBys(queryWrapper); 097 if (CollectionUtil.isNotEmpty(orderBys)) { 098 sql.append(OFFSET).append(0).append(ROWS_FETCH_NEXT).append(limitRows).append(ROWS_ONLY); 099 } else { 100 sql.insert(6, TOP + limitRows); 101 } 102 } 103 return sql; 104 }; 105 106 107 /** 108 * SqlServer 2005 limit 处理器 109 */ 110 LimitOffsetProcessor SQLSERVER_2005 = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { 111 if (limitRows != null) { 112 if (limitOffset == null) { 113 limitOffset = 0L; 114 } 115 116 List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper); 117 String originalSQL = sql.toString(); 118 String orderByString; 119 List<QueryOrderBy> orderBys = CPI.getOrderBys(queryWrapper); 120 if (orderBys == null || orderBys.isEmpty()) { 121 orderByString = "ORDER BY CURRENT_TIMESTAMP"; 122 } else { 123 StringBuilder orderBySql = new StringBuilder(ORDER_BY); 124 int index = 0; 125 for (QueryOrderBy orderBy : orderBys) { 126 orderBySql.append(orderBy.toSql(queryTables, dialect)); 127 if (index != orderBys.size() - 1) { 128 orderBySql.append(DELIMITER); 129 } 130 index++; 131 } 132 originalSQL = originalSQL.substring(0, sql.lastIndexOf(ORDER_BY)); 133 orderByString = orderBySql.toString(); 134 } 135 136 StringBuilder newSql = new StringBuilder("WITH temp_datas AS("); 137 newSql.append("SELECT ROW_NUMBER() OVER (").append(orderByString).append(") as __rn,").append(originalSQL.substring(6)); 138 newSql.append(")"); 139 newSql.append(" SELECT * FROM temp_datas WHERE __rn BETWEEN ").append(limitOffset + 1).append(" AND ").append(limitOffset + limitRows); 140 newSql.append(" ORDER BY __rn"); 141 return newSql; 142 } 143 return sql; 144 }; 145 146 147 /** 148 * Informix 的处理器 149 * 适合 {@link DbType#INFORMIX} 150 * 文档 {@link <a href="https://www.ibm.com/docs/en/informix-servers/14.10?topic=clause-restricting-return-values-skip-limit-first-options">https://www.ibm.com/docs/en/informix-servers/14.10?topic=clause-restricting-return-values-skip-limit-first-options</a>} 151 */ 152 LimitOffsetProcessor INFORMIX = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { 153 if (limitRows != null && limitOffset != null) { 154 // SELECT SKIP 2 FIRST 1 * FROM 155 sql.insert(6, SKIP + limitOffset + FIRST + limitRows); 156 } else if (limitRows != null) { 157 sql.insert(6, FIRST + limitRows); 158 } 159 return sql; 160 }; 161 162 163 /** 164 * 165 * SINODB 的处理器 166 * 适合 {@link DbType#SINODB} 167 */ 168 LimitOffsetProcessor SINODB = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { 169 if (limitRows != null && limitOffset != null) { 170 // SELECT SKIP 2 FIRST 1 * FROM 171 sql.insert(6, SKIP + limitOffset + FIRST + limitRows); 172 } else if (limitRows != null) { 173 sql.insert(6, FIRST + limitRows); 174 } 175 return sql; 176 }; 177 178 /** 179 * Firebird 的处理器 180 * 适合 {@link DbType#FIREBIRD} 181 */ 182 LimitOffsetProcessor FIREBIRD = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { 183 if (limitRows != null && limitOffset != null) { 184 // ROWS 2 TO 3 185 sql.append(ROWS).append(limitOffset).append(TO).append(limitOffset + limitRows); 186 } else if (limitRows != null) { 187 sql.insert(6, FIRST + limitRows); 188 } 189 return sql; 190 }; 191 192 /** 193 * Oracle11g及以下数据库的处理器 194 * 适合 {@link DbType#ORACLE,DbType#DM,DbType#GAUSS} 195 */ 196 LimitOffsetProcessor ORACLE = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { 197 if (limitRows != null) { 198 if (limitOffset == null) { 199 limitOffset = 0L; 200 } 201 StringBuilder newSql = new StringBuilder("SELECT * FROM (SELECT TEMP_DATAS.*, ROWNUM RN FROM ("); 202 newSql.append(sql); 203 newSql.append(") TEMP_DATAS WHERE ROWNUM <= ").append(limitOffset + limitRows).append(") WHERE RN > ").append(limitOffset); 204 return newSql; 205 } 206 return sql; 207 }; 208 209 /** 210 * Sybase 处理器 211 * 适合 {@link DbType#SYBASE} 212 */ 213 LimitOffsetProcessor SYBASE = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { 214 if (limitRows != null && limitOffset != null) { 215 //SELECT TOP 1 START AT 3 * FROM 216 sql.insert(6, TOP + limitRows + START_AT + (limitOffset + 1)); 217 } else if (limitRows != null) { 218 sql.insert(6, TOP + limitRows); 219 } 220 return sql; 221 }; 222 223 224}