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 // fix-bug:#I87AOA QueryWrapper 构建的SQL 与 执行的SQL不一致 117 List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper); 118 List<QueryTable> joinTables = CPI.getJoinTables(queryWrapper); 119 List<QueryTable> allTables = CollectionUtil.merge(queryTables, joinTables); 120 String originalSQL = sql.toString(); 121 String orderByString; 122 List<QueryOrderBy> orderBys = CPI.getOrderBys(queryWrapper); 123 if (orderBys == null || orderBys.isEmpty()) { 124 orderByString = "ORDER BY CURRENT_TIMESTAMP"; 125 } else { 126 StringBuilder orderBySql = new StringBuilder(ORDER_BY); 127 int index = 0; 128 for (QueryOrderBy orderBy : orderBys) { 129 orderBySql.append(orderBy.toSql(allTables, dialect)); 130 if (index != orderBys.size() - 1) { 131 orderBySql.append(DELIMITER); 132 } 133 index++; 134 } 135 originalSQL = originalSQL.substring(0, sql.lastIndexOf(ORDER_BY)); 136 orderByString = orderBySql.toString(); 137 } 138 139 StringBuilder newSql = new StringBuilder("WITH temp_datas AS("); 140 newSql.append("SELECT ROW_NUMBER() OVER (").append(orderByString).append(") as __rn,").append(originalSQL.substring(6)); 141 newSql.append(")"); 142 newSql.append(" SELECT * FROM temp_datas WHERE __rn BETWEEN ").append(limitOffset + 1).append(" AND ").append(limitOffset + limitRows); 143 newSql.append(" ORDER BY __rn"); 144 return newSql; 145 } 146 return sql; 147 }; 148 149 150 /** 151 * Informix 的处理器 152 * 适合 {@link DbType#INFORMIX} 153 * 文档 {@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>} 154 */ 155 LimitOffsetProcessor INFORMIX = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { 156 if (limitRows != null && limitOffset != null) { 157 // SELECT SKIP 2 FIRST 1 * FROM 158 sql.insert(6, SKIP + limitOffset + FIRST + limitRows); 159 } else if (limitRows != null) { 160 sql.insert(6, FIRST + limitRows); 161 } 162 return sql; 163 }; 164 165 166 /** 167 * 168 * SINODB 的处理器 169 * 适合 {@link DbType#SINODB} 170 */ 171 LimitOffsetProcessor SINODB = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { 172 if (limitRows != null && limitOffset != null) { 173 // SELECT SKIP 2 FIRST 1 * FROM 174 sql.insert(6, SKIP + limitOffset + FIRST + limitRows); 175 } else if (limitRows != null) { 176 sql.insert(6, FIRST + limitRows); 177 } 178 return sql; 179 }; 180 181 /** 182 * Firebird 的处理器 183 * 适合 {@link DbType#FIREBIRD} 184 */ 185 LimitOffsetProcessor FIREBIRD = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { 186 if (limitRows != null && limitOffset != null) { 187 // ROWS 2 TO 3 188 sql.append(ROWS).append(limitOffset).append(TO).append(limitOffset + limitRows); 189 } else if (limitRows != null) { 190 sql.insert(6, FIRST + limitRows); 191 } 192 return sql; 193 }; 194 195 /** 196 * Oracle11g及以下数据库的处理器 197 * 适合 {@link DbType#ORACLE,DbType#DM,DbType#GAUSS} 198 */ 199 LimitOffsetProcessor ORACLE = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { 200 if (limitRows != null) { 201 if (limitOffset == null) { 202 limitOffset = 0L; 203 } 204 StringBuilder newSql = new StringBuilder("SELECT * FROM (SELECT TEMP_DATAS.*, ROWNUM RN FROM ("); 205 newSql.append(sql); 206 newSql.append(") TEMP_DATAS WHERE ROWNUM <= ").append(limitOffset + limitRows).append(") WHERE RN > ").append(limitOffset); 207 return newSql; 208 } 209 return sql; 210 }; 211 212 /** 213 * Sybase 处理器 214 * 适合 {@link DbType#SYBASE} 215 */ 216 LimitOffsetProcessor SYBASE = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { 217 if (limitRows != null && limitOffset != null) { 218 //SELECT TOP 1 START AT 3 * FROM 219 sql.insert(6, TOP + limitRows + START_AT + (limitOffset + 1)); 220 } else if (limitRows != null) { 221 sql.insert(6, TOP + limitRows); 222 } 223 return sql; 224 }; 225 226 227}