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.QueryWrapper;
021import com.mybatisflex.core.util.CollectionUtil;
022
023import java.util.List;
024
025/**
026 * limit 和 offset 参数的处理器
027 */
028public interface LimitOffsetProcessor {
029
030    /**
031     * MySql 的处理器
032     * 适合 {@link DbType#MYSQL,DbType#MARIADB,DbType#H2,DbType#CLICK_HOUSE,DbType#XCloud}
033     */
034    LimitOffsetProcessor MYSQL = (sql, queryWrapper, limitRows, limitOffset) -> {
035        if (limitRows != null && limitOffset != null) {
036            sql.append(" LIMIT ").append(limitOffset).append(", ").append(limitRows);
037        } else if (limitRows != null) {
038            sql.append(" LIMIT ").append(limitRows);
039        }
040        return sql;
041    };
042
043    /**
044     * Postgresql 的处理器
045     * 适合  {@link DbType#POSTGRE_SQL,DbType#SQLITE,DbType#H2,DbType#HSQL,DbType#KINGBASE_ES,DbType#PHOENIX}
046     * 适合  {@link DbType#SAP_HANA,DbType#IMPALA,DbType#HIGH_GO,DbType#VERTICA,DbType#REDSHIFT}
047     * 适合  {@link DbType#OPENGAUSS,DbType#TDENGINE,DbType#UXDB}
048     */
049    LimitOffsetProcessor POSTGRESQL = (sql, queryWrapper, limitRows, limitOffset) -> {
050        if (limitRows != null && limitOffset != null) {
051            sql.append(" LIMIT ").append(limitRows).append(" OFFSET ").append(limitOffset);
052        } else if (limitRows != null) {
053            sql.append(" LIMIT ").append(limitRows);
054        }
055        return sql;
056    };
057
058    /**
059     * derby 的处理器
060     * 适合  {@link DbType#DERBY,DbType#ORACLE_12C,DbType#SQLSERVER ,DbType#POSTGRE_SQL}
061     */
062    LimitOffsetProcessor DERBY = (sql, queryWrapper, limitRows, limitOffset) -> {
063        if (limitRows != null && limitOffset != null) {
064            // OFFSET ** ROWS FETCH NEXT ** ROWS ONLY")
065            sql.append(" OFFSET ").append(limitOffset).append(" ROWS FETCH NEXT ").append(limitRows).append(" ROWS ONLY");
066        } else if (limitRows != null) {
067            sql.append(" OFFSET 0 ROWS FETCH NEXT ").append(limitRows).append(" ROWS ONLY");
068        }
069        return sql;
070    };
071
072    /**
073     * derby 的处理器
074     * 适合  {@link DbType#DERBY,DbType#ORACLE_12C,DbType#SQLSERVER ,DbType#POSTGRE_SQL}
075     */
076    LimitOffsetProcessor SQLSERVER = (sql, queryWrapper, limitRows, limitOffset) -> {
077        if (limitRows != null && limitOffset != null) {
078            // OFFSET ** ROWS FETCH NEXT ** ROWS ONLY")
079            sql.append(" OFFSET ").append(limitOffset).append(" ROWS FETCH NEXT ").append(limitRows).append(" ROWS ONLY");
080        } else if (limitRows != null) {
081            List<QueryOrderBy> orderBys = CPI.getOrderBys(queryWrapper);
082            if (CollectionUtil.isNotEmpty(orderBys)) {
083                sql.append(" OFFSET 0 ROWS FETCH NEXT ").append(limitRows).append(" ROWS ONLY");
084            } else {
085                sql.insert(6, " TOP " + limitRows);
086            }
087        }
088        return sql;
089    };
090
091
092    /**
093     * Informix 的处理器
094     * 适合  {@link DbType#INFORMIX}
095     * 文档 {@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>}
096     */
097    LimitOffsetProcessor INFORMIX = (sql, queryWrapper, limitRows, limitOffset) -> {
098        if (limitRows != null && limitOffset != null) {
099            // SELECT SKIP 2 FIRST 1 * FROM
100            sql.insert(6, " SKIP " + limitOffset + " FIRST " + limitRows);
101        } else if (limitRows != null) {
102            sql.insert(6, " FIRST " + limitRows);
103        }
104        return sql;
105    };
106
107    /**
108     * Firebird 的处理器
109     * 适合  {@link DbType#FIREBIRD}
110     */
111    LimitOffsetProcessor FIREBIRD = (sql, queryWrapper, limitRows, limitOffset) -> {
112        if (limitRows != null && limitOffset != null) {
113            // ROWS 2 TO 3
114            sql.append(" ROWS ").append(limitOffset).append(" TO ").append(limitOffset + limitRows);
115        } else if (limitRows != null) {
116            sql.insert(6, " FIRST " + limitRows);
117        }
118        return sql;
119    };
120
121    /**
122     * Oracle11g及以下数据库的处理器
123     * 适合  {@link DbType#ORACLE,DbType#DM,DbType#GAUSS}
124     */
125    LimitOffsetProcessor ORACLE = (sql, queryWrapper, limitRows, limitOffset) -> {
126        if (limitRows != null) {
127            if (limitOffset == null) {
128                limitOffset = 0;
129            }
130            StringBuilder newSql = new StringBuilder("SELECT * FROM (SELECT TEMP_DATAS.*, ROWNUM RN FROM (");
131            newSql.append(sql);
132            newSql.append(") TEMP_DATAS WHERE  ROWNUM <=").append(limitOffset + limitRows).append(") WHERE RN >").append(limitOffset);
133            return newSql;
134        }
135        return sql;
136    };
137
138    /**
139     * Sybase 处理器
140     * 适合  {@link DbType#SYBASE}
141     */
142    LimitOffsetProcessor SYBASE = (sql, queryWrapper, limitRows, limitOffset) -> {
143        if (limitRows != null && limitOffset != null) {
144            //SELECT TOP 1 START AT 3 * FROM
145            sql.insert(6, " TOP " + limitRows + " START AT " + (limitOffset + 1));
146        } else if (limitRows != null) {
147            sql.insert(6, " TOP " + limitRows);
148        }
149        return sql;
150    };
151
152
153    /**
154     * 处理构建 limit 和 offset
155     *
156     * @param sql          已经构建的 sql
157     * @param queryWrapper 参数内容
158     * @param limitRows    用户传入的 limit 参数 可能为 null
159     * @param limitOffset  用户传入的 offset 参数,可能为 null
160     */
161    StringBuilder process(StringBuilder sql, QueryWrapper queryWrapper, Integer limitRows, Integer limitOffset);
162}