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