001/* 002 * Copyright (c) 2022-2025, 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 static com.mybatisflex.core.constant.SqlConsts.*; 019 020import com.mybatisflex.core.query.CPI; 021import com.mybatisflex.core.query.QueryOrderBy; 022import com.mybatisflex.core.query.QueryTable; 023import com.mybatisflex.core.query.QueryWrapper; 024import com.mybatisflex.core.util.CollectionUtil; 025import java.util.List; 026 027/** 028 * limit 和 offset 参数的处理器 029 */ 030public interface LimitOffsetProcessor { 031 032 /** 033 * 处理构建 limit 和 offset 034 * 035 * @param dialect 数据方言 036 * @param sql 已经构建的 sql 037 * @param queryWrapper 参数内容 038 * @param limitRows 用户传入的 limit 参数 可能为 null 039 * @param limitOffset 用户传入的 offset 参数,可能为 null 040 */ 041 StringBuilder process(IDialect dialect, StringBuilder sql, QueryWrapper queryWrapper, Long limitRows, Long limitOffset); 042 043 044 /** 045 * MySql 的处理器 046 * 适合 {@link DbType#MYSQL,DbType#MARIADB,DbType#H2,DbType#CLICK_HOUSE,DbType#XCloud} 047 */ 048 LimitOffsetProcessor MYSQL = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { 049 if (limitRows != null && limitOffset != null) { 050 sql.append(LIMIT).append(limitOffset).append(DELIMITER).append(limitRows); 051 } else if (limitRows != null) { 052 sql.append(LIMIT).append(limitRows); 053 } 054 return sql; 055 }; 056 /** 057 * Postgresql 的处理器 058 * 适合 {@link DbType#POSTGRE_SQL,DbType#SQLITE,DbType#H2,DbType#HSQL,DbType#KINGBASE_ES,DbType#PHOENIX} 059 * 适合 {@link DbType#SAP_HANA,DbType#IMPALA,DbType#HIGH_GO,DbType#VERTICA,DbType#REDSHIFT} 060 * 适合 {@link DbType#OPENGAUSS,DbType#TDENGINE,DbType#UXDB} 061 */ 062 LimitOffsetProcessor POSTGRESQL = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { 063 if (limitRows != null && limitOffset != null) { 064 sql.append(LIMIT).append(limitRows).append(OFFSET).append(limitOffset); 065 } else if (limitRows != null) { 066 sql.append(LIMIT).append(limitRows); 067 } 068 return sql; 069 }; 070 /** 071 * derby 的处理器 072 * 适合 {@link DbType#DERBY,DbType#ORACLE_12C,DbType#SQLSERVER ,DbType#POSTGRE_SQL} 073 */ 074 LimitOffsetProcessor DERBY = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { 075 if (limitRows != null && limitOffset != null) { 076 // OFFSET ** ROWS FETCH NEXT ** ROWS ONLY") 077 sql.append(OFFSET).append(limitOffset).append(ROWS_FETCH_NEXT).append(limitRows).append(ROWS_ONLY); 078 } else if (limitRows != null) { 079 sql.append(OFFSET).append(0).append(ROWS_FETCH_NEXT).append(limitRows).append(ROWS_ONLY); 080 } 081 return sql; 082 }; 083 /** 084 * derby 的处理器 085 * 适合 {@link DbType#DERBY,DbType#ORACLE_12C,DbType#SQLSERVER ,DbType#POSTGRE_SQL} 086 */ 087 LimitOffsetProcessor SQLSERVER = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { 088 if (limitRows != null && limitOffset != null) { 089 // OFFSET ** ROWS FETCH NEXT ** ROWS ONLY") 090 sql.append(OFFSET).append(limitOffset).append(ROWS_FETCH_NEXT).append(limitRows).append(ROWS_ONLY); 091 } else if (limitRows != null) { 092 List<QueryOrderBy> orderBys = CPI.getOrderBys(queryWrapper); 093 if (CollectionUtil.isNotEmpty(orderBys)) { 094 sql.append(OFFSET).append(0).append(ROWS_FETCH_NEXT).append(limitRows).append(ROWS_ONLY); 095 } else { 096 sql.insert(6, TOP + limitRows); 097 } 098 } 099 return sql; 100 }; 101 /** 102 * SqlServer 2005 limit 处理器 103 */ 104 LimitOffsetProcessor SQLSERVER_2005 = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { 105 if (limitRows != null) { 106 if (limitOffset == null) { 107 limitOffset = 0L; 108 } 109 110 // fix-bug:#I87AOA QueryWrapper 构建的SQL 与 执行的SQL不一致 111 List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper); 112 List<QueryTable> joinTables = CPI.getJoinTables(queryWrapper); 113 List<QueryTable> allTables = CollectionUtil.merge(queryTables, joinTables); 114 String originalSQL = sql.toString(); 115 String orderByString; 116 List<QueryOrderBy> orderBys = CPI.getOrderBys(queryWrapper); 117 if (orderBys == null || orderBys.isEmpty()) { 118 orderByString = "ORDER BY CURRENT_TIMESTAMP"; 119 } else { 120 StringBuilder orderBySql = new StringBuilder(ORDER_BY); 121 int index = 0; 122 for (QueryOrderBy orderBy : orderBys) { 123 orderBySql.append(orderBy.toSql(allTables, dialect)); 124 if (index != orderBys.size() - 1) { 125 orderBySql.append(DELIMITER); 126 } 127 index++; 128 } 129 originalSQL = originalSQL.substring(0, sql.lastIndexOf(ORDER_BY)); 130 orderByString = orderBySql.toString(); 131 } 132 133 StringBuilder newSql = new StringBuilder(); 134 //fix SqlServer 多表关联查询,主表去重,执行SQL异常 https://gitee.com/mybatis-flex/mybatis-flex/issues/IABEJG 135 newSql.append("WITH temp_datas AS(SELECT __Tab.*, ROW_NUMBER() OVER ( ").append(orderByString) 136 .append(") as __rn ").append(" FROM ( ").append(originalSQL).append(" ) as __Tab ) "); 137 newSql.append(" SELECT * FROM temp_datas WHERE __rn BETWEEN ") 138 .append(limitOffset + 1).append(" AND ").append(limitOffset + limitRows); 139 newSql.append(" ORDER BY __rn"); 140 return newSql; 141 } 142 return sql; 143 }; 144 /** 145 * Informix 的处理器 146 * 适合 {@link DbType#INFORMIX} 147 * 文档 {@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>} 148 */ 149 LimitOffsetProcessor INFORMIX = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { 150 if (limitRows != null && limitOffset != null) { 151 // SELECT SKIP 2 FIRST 1 * FROM 152 sql.insert(6, SKIP + limitOffset + FIRST + limitRows); 153 } else if (limitRows != null) { 154 sql.insert(6, FIRST + limitRows); 155 } 156 return sql; 157 }; 158 /** 159 * 160 * SINODB 的处理器 161 * 适合 {@link DbType#SINODB} 162 */ 163 LimitOffsetProcessor SINODB = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { 164 if (limitRows != null && limitOffset != null) { 165 // SELECT SKIP 2 FIRST 1 * FROM 166 sql.insert(6, SKIP + limitOffset + FIRST + limitRows); 167 } else if (limitRows != null) { 168 sql.insert(6, FIRST + limitRows); 169 } 170 return sql; 171 }; 172 /** 173 * Firebird 的处理器 174 * 适合 {@link DbType#FIREBIRD} 175 */ 176 LimitOffsetProcessor FIREBIRD = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { 177 if (limitRows != null && limitOffset != null) { 178 // ROWS 2 TO 3 179 sql.append(ROWS).append(limitOffset).append(TO).append(limitOffset + limitRows); 180 } else if (limitRows != null) { 181 sql.insert(6, FIRST + limitRows); 182 } 183 return sql; 184 }; 185 /** 186 * Oracle11g及以下数据库的处理器 187 * 适合 {@link DbType#ORACLE,DbType#DM,DbType#GAUSS} 188 */ 189 LimitOffsetProcessor ORACLE = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { 190 if (limitRows != null) { 191 if (limitOffset == null) { 192 limitOffset = 0L; 193 } 194 StringBuilder newSql = new StringBuilder("SELECT * FROM (SELECT TEMP_DATAS.*, ROWNUM RN FROM ("); 195 newSql.append(sql); 196 newSql.append(") TEMP_DATAS WHERE ROWNUM <= ") 197 .append(limitOffset + limitRows) 198 .append(") WHERE RN > ") 199 .append(limitOffset); 200 return newSql; 201 } 202 return sql; 203 }; 204 /** 205 * Sybase 处理器 206 * 适合 {@link DbType#SYBASE} 207 */ 208 LimitOffsetProcessor SYBASE = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { 209 if (limitRows != null && limitOffset != null) { 210 //SELECT TOP 1 START AT 3 * FROM 211 sql.insert(6, TOP + limitRows + START_AT + (limitOffset + 1)); 212 } else if (limitRows != null) { 213 sql.insert(6, TOP + limitRows); 214 } 215 return sql; 216 }; 217 218 219}