feat: add sqlServer 2005 LimitOffsetProcessor

This commit is contained in:
开源海哥 2023-07-10 11:57:35 +08:00
parent 81016ec601
commit 9582f88cf7
4 changed files with 286 additions and 261 deletions

View File

@ -58,6 +58,10 @@ public enum DbType {
* SQLSERVER * SQLSERVER
*/ */
SQLSERVER("sqlserver", "SQLServer 数据库"), SQLSERVER("sqlserver", "SQLServer 数据库"),
/**
* SqlServer 2005 数据库
*/
SQLSERVER_2005("sqlserver_2005", "SQLServer 数据库"),
/** /**
* DM * DM
*/ */

View File

@ -31,148 +31,151 @@ import java.util.regex.Pattern;
*/ */
public class DbTypeUtil { public class DbTypeUtil {
private DbTypeUtil() {} private DbTypeUtil() {
}
/** /**
* 获取当前配置的 DbType * 获取当前配置的 DbType
*/ */
public static DbType getDbType(DataSource dataSource) { public static DbType getDbType(DataSource dataSource) {
String jdbcUrl = getJdbcUrl(dataSource); String jdbcUrl = getJdbcUrl(dataSource);
if (StringUtil.isNotBlank(jdbcUrl)) { if (StringUtil.isNotBlank(jdbcUrl)) {
return parseDbType(jdbcUrl); return parseDbType(jdbcUrl);
} }
throw new IllegalStateException("Can not get dataSource jdbcUrl: " + dataSource.getClass().getName()); throw new IllegalStateException("Can not get dataSource jdbcUrl: " + dataSource.getClass().getName());
} }
/** /**
* 通过数据源中获取 jdbc url 配置 * 通过数据源中获取 jdbc url 配置
* 符合 HikariCP, druid, c3p0, DBCP, beecp 数据源框架 以及 MyBatis UnpooledDataSource 的获取规则 * 符合 HikariCP, druid, c3p0, DBCP, beecp 数据源框架 以及 MyBatis UnpooledDataSource 的获取规则
* UnpooledDataSource 参考 @{@link UnpooledDataSource#getUrl()} * UnpooledDataSource 参考 @{@link UnpooledDataSource#getUrl()}
* *
* @return jdbc url 配置 * @return jdbc url 配置
*/ */
public static String getJdbcUrl(DataSource dataSource) { public static String getJdbcUrl(DataSource dataSource) {
String[] methodNames = new String[]{"getUrl", "getJdbcUrl"}; String[] methodNames = new String[]{"getUrl", "getJdbcUrl"};
for (String methodName : methodNames) { for (String methodName : methodNames) {
try { try {
Method method = dataSource.getClass().getMethod(methodName); Method method = dataSource.getClass().getMethod(methodName);
return (String) method.invoke(dataSource); return (String) method.invoke(dataSource);
} catch (Exception e) { } catch (Exception e) {
//ignore //ignore
} }
} }
Connection connection = null; Connection connection = null;
try { try {
connection = dataSource.getConnection(); connection = dataSource.getConnection();
return connection.getMetaData().getURL(); return connection.getMetaData().getURL();
} catch (Exception e) { } catch (Exception e) {
throw FlexExceptions.wrap("Can not get the dataSource jdbcUrl", e); throw FlexExceptions.wrap("Can not get the dataSource jdbcUrl", e);
} finally { } finally {
if (connection != null) { if (connection != null) {
try { try {
connection.close(); connection.close();
} catch (SQLException e) { //ignore } catch (SQLException e) { //ignore
} }
} }
} }
} }
/** /**
* 参考 druid MyBatis-plus JdbcUtils * 参考 druid MyBatis-plus JdbcUtils
* {@link com.alibaba.druid.util.JdbcUtils#getDbType(String, String)} * {@link com.alibaba.druid.util.JdbcUtils#getDbType(String, String)}
* {@link com.baomidou.mybatisplus.extension.toolkit.JdbcUtils#getDbType(String)} * {@link com.baomidou.mybatisplus.extension.toolkit.JdbcUtils#getDbType(String)}
* *
* @param jdbcUrl jdbcURL * @param jdbcUrl jdbcURL
* @return 返回数据库类型 * @return 返回数据库类型
*/ */
public static DbType parseDbType(String jdbcUrl) { public static DbType parseDbType(String jdbcUrl) {
jdbcUrl = jdbcUrl.toLowerCase(); jdbcUrl = jdbcUrl.toLowerCase();
if (jdbcUrl.contains(":mysql:") || jdbcUrl.contains(":cobar:")) { if (jdbcUrl.contains(":mysql:") || jdbcUrl.contains(":cobar:")) {
return DbType.MYSQL; return DbType.MYSQL;
} else if (jdbcUrl.contains(":mariadb:")) { } else if (jdbcUrl.contains(":mariadb:")) {
return DbType.MARIADB; return DbType.MARIADB;
} else if (jdbcUrl.contains(":oracle:")) { } else if (jdbcUrl.contains(":oracle:")) {
return DbType.ORACLE; return DbType.ORACLE;
} else if (jdbcUrl.contains(":sqlserver:") || jdbcUrl.contains(":microsoft:") || jdbcUrl.contains(":sqlserver2012:")) { } else if (jdbcUrl.contains(":sqlserver2012:")) {
return DbType.SQLSERVER; return DbType.SQLSERVER;
} else if (jdbcUrl.contains(":postgresql:")) { } else if (jdbcUrl.contains(":sqlserver:") || jdbcUrl.contains(":microsoft:")) {
return DbType.POSTGRE_SQL; return DbType.SQLSERVER_2005;
} else if (jdbcUrl.contains(":hsqldb:")) { } else if (jdbcUrl.contains(":postgresql:")) {
return DbType.HSQL; return DbType.POSTGRE_SQL;
} else if (jdbcUrl.contains(":db2:")) { } else if (jdbcUrl.contains(":hsqldb:")) {
return DbType.DB2; return DbType.HSQL;
} else if (jdbcUrl.contains(":sqlite:")) { } else if (jdbcUrl.contains(":db2:")) {
return DbType.SQLITE; return DbType.DB2;
} else if (jdbcUrl.contains(":h2:")) { } else if (jdbcUrl.contains(":sqlite:")) {
return DbType.H2; return DbType.SQLITE;
} else if (isMatchedRegex(":dm\\d*:", jdbcUrl)) { } else if (jdbcUrl.contains(":h2:")) {
return DbType.DM; return DbType.H2;
} else if (jdbcUrl.contains(":xugu:")) { } else if (isMatchedRegex(":dm\\d*:", jdbcUrl)) {
return DbType.XUGU; return DbType.DM;
} else if (isMatchedRegex(":kingbase\\d*:", jdbcUrl)) { } else if (jdbcUrl.contains(":xugu:")) {
return DbType.KINGBASE_ES; return DbType.XUGU;
} else if (jdbcUrl.contains(":phoenix:")) { } else if (isMatchedRegex(":kingbase\\d*:", jdbcUrl)) {
return DbType.PHOENIX; return DbType.KINGBASE_ES;
} else if (jdbcUrl.contains(":zenith:")) { } else if (jdbcUrl.contains(":phoenix:")) {
return DbType.GAUSS; return DbType.PHOENIX;
} else if (jdbcUrl.contains(":gbase:")) { } else if (jdbcUrl.contains(":zenith:")) {
return DbType.GBASE; return DbType.GAUSS;
} else if (jdbcUrl.contains(":gbasedbt-sqli:") || jdbcUrl.contains(":informix-sqli:")) { } else if (jdbcUrl.contains(":gbase:")) {
return DbType.GBASE_8S; return DbType.GBASE;
} else if (jdbcUrl.contains(":ch:") || jdbcUrl.contains(":clickhouse:")) { } else if (jdbcUrl.contains(":gbasedbt-sqli:") || jdbcUrl.contains(":informix-sqli:")) {
return DbType.CLICK_HOUSE; return DbType.GBASE_8S;
} else if (jdbcUrl.contains(":oscar:")) { } else if (jdbcUrl.contains(":ch:") || jdbcUrl.contains(":clickhouse:")) {
return DbType.OSCAR; return DbType.CLICK_HOUSE;
} else if (jdbcUrl.contains(":sybase:")) { } else if (jdbcUrl.contains(":oscar:")) {
return DbType.SYBASE; return DbType.OSCAR;
} else if (jdbcUrl.contains(":oceanbase:")) { } else if (jdbcUrl.contains(":sybase:")) {
return DbType.OCEAN_BASE; return DbType.SYBASE;
} else if (jdbcUrl.contains(":highgo:")) { } else if (jdbcUrl.contains(":oceanbase:")) {
return DbType.HIGH_GO; return DbType.OCEAN_BASE;
} else if (jdbcUrl.contains(":cubrid:")) { } else if (jdbcUrl.contains(":highgo:")) {
return DbType.CUBRID; return DbType.HIGH_GO;
} else if (jdbcUrl.contains(":goldilocks:")) { } else if (jdbcUrl.contains(":cubrid:")) {
return DbType.GOLDILOCKS; return DbType.CUBRID;
} else if (jdbcUrl.contains(":csiidb:")) { } else if (jdbcUrl.contains(":goldilocks:")) {
return DbType.CSIIDB; return DbType.GOLDILOCKS;
} else if (jdbcUrl.contains(":sap:")) { } else if (jdbcUrl.contains(":csiidb:")) {
return DbType.SAP_HANA; return DbType.CSIIDB;
} else if (jdbcUrl.contains(":impala:")) { } else if (jdbcUrl.contains(":sap:")) {
return DbType.IMPALA; return DbType.SAP_HANA;
} else if (jdbcUrl.contains(":vertica:")) { } else if (jdbcUrl.contains(":impala:")) {
return DbType.VERTICA; return DbType.IMPALA;
} else if (jdbcUrl.contains(":xcloud:")) { } else if (jdbcUrl.contains(":vertica:")) {
return DbType.XCloud; return DbType.VERTICA;
} else if (jdbcUrl.contains(":firebirdsql:")) { } else if (jdbcUrl.contains(":xcloud:")) {
return DbType.FIREBIRD; return DbType.XCloud;
} else if (jdbcUrl.contains(":redshift:")) { } else if (jdbcUrl.contains(":firebirdsql:")) {
return DbType.REDSHIFT; return DbType.FIREBIRD;
} else if (jdbcUrl.contains(":opengauss:")) { } else if (jdbcUrl.contains(":redshift:")) {
return DbType.OPENGAUSS; return DbType.REDSHIFT;
} else if (jdbcUrl.contains(":taos:") || jdbcUrl.contains(":taos-rs:")) { } else if (jdbcUrl.contains(":opengauss:")) {
return DbType.TDENGINE; return DbType.OPENGAUSS;
} else if (jdbcUrl.contains(":informix")) { } else if (jdbcUrl.contains(":taos:") || jdbcUrl.contains(":taos-rs:")) {
return DbType.INFORMIX; return DbType.TDENGINE;
} else if (jdbcUrl.contains(":uxdb:")) { } else if (jdbcUrl.contains(":informix")) {
return DbType.UXDB; return DbType.INFORMIX;
} else if (jdbcUrl.contains(":greenplum:")) { } else if (jdbcUrl.contains(":uxdb:")) {
return DbType.GREENPLUM; return DbType.UXDB;
} else { } else if (jdbcUrl.contains(":greenplum:")) {
return DbType.OTHER; return DbType.GREENPLUM;
} } else {
} return DbType.OTHER;
}
}
/** /**
* 正则匹配验证成功返回 true验证失败返回 false * 正则匹配验证成功返回 true验证失败返回 false
*/ */
public static boolean isMatchedRegex(String regex, String jdbcUrl) { public static boolean isMatchedRegex(String regex, String jdbcUrl) {
if (null == jdbcUrl) { if (null == jdbcUrl) {
return false; return false;
} }
return Pattern.compile(regex).matcher(jdbcUrl).find(); return Pattern.compile(regex).matcher(jdbcUrl).find();
} }
} }

View File

@ -134,6 +134,8 @@ public class DialectFactory {
return new CommonsDialectImpl(KeywordWrap.DOUBLE_QUOTATION, LimitOffsetProcessor.DERBY); return new CommonsDialectImpl(KeywordWrap.DOUBLE_QUOTATION, LimitOffsetProcessor.DERBY);
case SQLSERVER: case SQLSERVER:
return new CommonsDialectImpl(KeywordWrap.SQUARE_BRACKETS, LimitOffsetProcessor.SQLSERVER); return new CommonsDialectImpl(KeywordWrap.SQUARE_BRACKETS, LimitOffsetProcessor.SQLSERVER);
case SQLSERVER_2005:
return new CommonsDialectImpl(KeywordWrap.SQUARE_BRACKETS, LimitOffsetProcessor.SQLSERVER_2005);
case INFORMIX: case INFORMIX:
return new CommonsDialectImpl(KeywordWrap.DOUBLE_QUOTATION, LimitOffsetProcessor.INFORMIX); return new CommonsDialectImpl(KeywordWrap.DOUBLE_QUOTATION, LimitOffsetProcessor.INFORMIX);
case SYBASE: case SYBASE:

View File

@ -29,136 +29,152 @@ import static com.mybatisflex.core.constant.SqlConsts.*;
*/ */
public interface LimitOffsetProcessor { public interface LimitOffsetProcessor {
/** /**
* MySql 的处理器 * MySql 的处理器
* 适合 {@link DbType#MYSQL,DbType#MARIADB,DbType#H2,DbType#CLICK_HOUSE,DbType#XCloud} * 适合 {@link DbType#MYSQL,DbType#MARIADB,DbType#H2,DbType#CLICK_HOUSE,DbType#XCloud}
*/ */
LimitOffsetProcessor MYSQL = (sql, queryWrapper, limitRows, limitOffset) -> { LimitOffsetProcessor MYSQL = (sql, queryWrapper, limitRows, limitOffset) -> {
if (limitRows != null && limitOffset != null) { if (limitRows != null && limitOffset != null) {
sql.append(LIMIT).append(limitOffset).append(DELIMITER).append(limitRows); sql.append(LIMIT).append(limitOffset).append(DELIMITER).append(limitRows);
} else if (limitRows != null) { } else if (limitRows != null) {
sql.append(LIMIT).append(limitRows); sql.append(LIMIT).append(limitRows);
} }
return sql; return sql;
}; };
/** /**
* Postgresql 的处理器 * Postgresql 的处理器
* 适合 {@link DbType#POSTGRE_SQL,DbType#SQLITE,DbType#H2,DbType#HSQL,DbType#KINGBASE_ES,DbType#PHOENIX} * 适合 {@link DbType#POSTGRE_SQL,DbType#SQLITE,DbType#H2,DbType#HSQL,DbType#KINGBASE_ES,DbType#PHOENIX}
* 适合 {@link DbType#SAP_HANA,DbType#IMPALA,DbType#HIGH_GO,DbType#VERTICA,DbType#REDSHIFT} * 适合 {@link DbType#SAP_HANA,DbType#IMPALA,DbType#HIGH_GO,DbType#VERTICA,DbType#REDSHIFT}
* 适合 {@link DbType#OPENGAUSS,DbType#TDENGINE,DbType#UXDB} * 适合 {@link DbType#OPENGAUSS,DbType#TDENGINE,DbType#UXDB}
*/ */
LimitOffsetProcessor POSTGRESQL = (sql, queryWrapper, limitRows, limitOffset) -> { LimitOffsetProcessor POSTGRESQL = (sql, queryWrapper, limitRows, limitOffset) -> {
if (limitRows != null && limitOffset != null) { if (limitRows != null && limitOffset != null) {
sql.append(LIMIT).append(limitRows).append(OFFSET).append(limitOffset); sql.append(LIMIT).append(limitRows).append(OFFSET).append(limitOffset);
} else if (limitRows != null) { } else if (limitRows != null) {
sql.append(LIMIT).append(limitRows); sql.append(LIMIT).append(limitRows);
} }
return sql; return sql;
}; };
/** /**
* derby 的处理器 * derby 的处理器
* 适合 {@link DbType#DERBY,DbType#ORACLE_12C,DbType#SQLSERVER ,DbType#POSTGRE_SQL} * 适合 {@link DbType#DERBY,DbType#ORACLE_12C,DbType#SQLSERVER ,DbType#POSTGRE_SQL}
*/ */
LimitOffsetProcessor DERBY = (sql, queryWrapper, limitRows, limitOffset) -> { LimitOffsetProcessor DERBY = (sql, queryWrapper, limitRows, limitOffset) -> {
if (limitRows != null && limitOffset != null) { if (limitRows != null && limitOffset != null) {
// OFFSET ** ROWS FETCH NEXT ** ROWS ONLY") // OFFSET ** ROWS FETCH NEXT ** ROWS ONLY")
sql.append(OFFSET).append(limitOffset).append(ROWS_FETCH_NEXT).append(limitRows).append(ROWS_ONLY); sql.append(OFFSET).append(limitOffset).append(ROWS_FETCH_NEXT).append(limitRows).append(ROWS_ONLY);
} else if (limitRows != null) { } else if (limitRows != null) {
sql.append(OFFSET).append(0).append(ROWS_FETCH_NEXT).append(limitRows).append(ROWS_ONLY); sql.append(OFFSET).append(0).append(ROWS_FETCH_NEXT).append(limitRows).append(ROWS_ONLY);
} }
return sql; return sql;
}; };
/** /**
* derby 的处理器 * derby 的处理器
* 适合 {@link DbType#DERBY,DbType#ORACLE_12C,DbType#SQLSERVER ,DbType#POSTGRE_SQL} * 适合 {@link DbType#DERBY,DbType#ORACLE_12C,DbType#SQLSERVER ,DbType#POSTGRE_SQL}
*/ */
LimitOffsetProcessor SQLSERVER = (sql, queryWrapper, limitRows, limitOffset) -> { LimitOffsetProcessor SQLSERVER = (sql, queryWrapper, limitRows, limitOffset) -> {
if (limitRows != null && limitOffset != null) { if (limitRows != null && limitOffset != null) {
// OFFSET ** ROWS FETCH NEXT ** ROWS ONLY") // OFFSET ** ROWS FETCH NEXT ** ROWS ONLY")
sql.append(OFFSET).append(limitOffset).append(ROWS_FETCH_NEXT).append(limitRows).append(ROWS_ONLY); sql.append(OFFSET).append(limitOffset).append(ROWS_FETCH_NEXT).append(limitRows).append(ROWS_ONLY);
} else if (limitRows != null) { } else if (limitRows != null) {
List<QueryOrderBy> orderBys = CPI.getOrderBys(queryWrapper); List<QueryOrderBy> orderBys = CPI.getOrderBys(queryWrapper);
if (CollectionUtil.isNotEmpty(orderBys)) { if (CollectionUtil.isNotEmpty(orderBys)) {
sql.append(OFFSET).append(0).append(ROWS_FETCH_NEXT).append(limitRows).append(ROWS_ONLY); sql.append(OFFSET).append(0).append(ROWS_FETCH_NEXT).append(limitRows).append(ROWS_ONLY);
} else { } else {
sql.insert(6, TOP + limitRows); sql.insert(6, TOP + limitRows);
} }
} }
return sql; return sql;
}; };
/** /**
* Informix 的处理器 * SqlServer 2005 limit 处理器
* 适合 {@link DbType#INFORMIX} */
* 文档 {@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>} LimitOffsetProcessor SQLSERVER_2005 = (sql, queryWrapper, limitRows, limitOffset) -> {
*/ if (limitRows != null) {
LimitOffsetProcessor INFORMIX = (sql, queryWrapper, limitRows, limitOffset) -> { if (limitOffset == null) {
if (limitRows != null && limitOffset != null) { limitOffset = 0;
// SELECT SKIP 2 FIRST 1 * FROM }
sql.insert(6, SKIP + limitOffset + FIRST + limitRows); StringBuilder newSql = new StringBuilder("SELECT * FROM (SELECT TEMP_DATAS.*, ROW_NUMBER() OVER() AS RN FROM (");
} else if (limitRows != null) { newSql.append(sql).append(") AS TEMP_DATAS) WHERE RN > ").append(limitOffset).append(" AND RN <= ").append(limitRows + limitRows);
sql.insert(6, FIRST + limitRows); return newSql;
} }
return sql; return sql;
}; };
/**
* Firebird 的处理器
* 适合 {@link DbType#FIREBIRD}
*/
LimitOffsetProcessor FIREBIRD = (sql, queryWrapper, limitRows, limitOffset) -> {
if (limitRows != null && limitOffset != null) {
// ROWS 2 TO 3
sql.append(ROWS).append(limitOffset).append(TO).append(limitOffset + limitRows);
} else if (limitRows != null) {
sql.insert(6, FIRST + limitRows);
}
return sql;
};
/**
* Oracle11g及以下数据库的处理器
* 适合 {@link DbType#ORACLE,DbType#DM,DbType#GAUSS}
*/
LimitOffsetProcessor ORACLE = (sql, queryWrapper, limitRows, limitOffset) -> {
if (limitRows != null) {
if (limitOffset == null) {
limitOffset = 0;
}
StringBuilder newSql = new StringBuilder("SELECT * FROM (SELECT TEMP_DATAS.*, ROWNUM RN FROM (");
newSql.append(sql);
newSql.append(") TEMP_DATAS WHERE ROWNUM <= ").append(limitOffset + limitRows).append(") WHERE RN > ").append(limitOffset);
return newSql;
}
return sql;
};
/**
* Sybase 处理器
* 适合 {@link DbType#SYBASE}
*/
LimitOffsetProcessor SYBASE = (sql, queryWrapper, limitRows, limitOffset) -> {
if (limitRows != null && limitOffset != null) {
//SELECT TOP 1 START AT 3 * FROM
sql.insert(6, TOP + limitRows + START_AT + (limitOffset + 1));
} else if (limitRows != null) {
sql.insert(6, TOP + limitRows);
}
return sql;
};
/** /**
* 处理构建 limit offset * Informix 的处理器
* * 适合 {@link DbType#INFORMIX}
* @param sql 已经构建的 sql * 文档 {@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>}
* @param queryWrapper 参数内容 */
* @param limitRows 用户传入的 limit 参数 可能为 null LimitOffsetProcessor INFORMIX = (sql, queryWrapper, limitRows, limitOffset) -> {
* @param limitOffset 用户传入的 offset 参数可能为 null if (limitRows != null && limitOffset != null) {
*/ // SELECT SKIP 2 FIRST 1 * FROM
StringBuilder process(StringBuilder sql, QueryWrapper queryWrapper, Integer limitRows, Integer limitOffset); sql.insert(6, SKIP + limitOffset + FIRST + limitRows);
} else if (limitRows != null) {
sql.insert(6, FIRST + limitRows);
}
return sql;
};
/**
* Firebird 的处理器
* 适合 {@link DbType#FIREBIRD}
*/
LimitOffsetProcessor FIREBIRD = (sql, queryWrapper, limitRows, limitOffset) -> {
if (limitRows != null && limitOffset != null) {
// ROWS 2 TO 3
sql.append(ROWS).append(limitOffset).append(TO).append(limitOffset + limitRows);
} else if (limitRows != null) {
sql.insert(6, FIRST + limitRows);
}
return sql;
};
/**
* Oracle11g及以下数据库的处理器
* 适合 {@link DbType#ORACLE,DbType#DM,DbType#GAUSS}
*/
LimitOffsetProcessor ORACLE = (sql, queryWrapper, limitRows, limitOffset) -> {
if (limitRows != null) {
if (limitOffset == null) {
limitOffset = 0;
}
StringBuilder newSql = new StringBuilder("SELECT * FROM (SELECT TEMP_DATAS.*, ROWNUM RN FROM (");
newSql.append(sql);
newSql.append(") TEMP_DATAS WHERE ROWNUM <= ").append(limitOffset + limitRows).append(") WHERE RN > ").append(limitOffset);
return newSql;
}
return sql;
};
/**
* Sybase 处理器
* 适合 {@link DbType#SYBASE}
*/
LimitOffsetProcessor SYBASE = (sql, queryWrapper, limitRows, limitOffset) -> {
if (limitRows != null && limitOffset != null) {
//SELECT TOP 1 START AT 3 * FROM
sql.insert(6, TOP + limitRows + START_AT + (limitOffset + 1));
} else if (limitRows != null) {
sql.insert(6, TOP + limitRows);
}
return sql;
};
/**
* 处理构建 limit offset
*
* @param sql 已经构建的 sql
* @param queryWrapper 参数内容
* @param limitRows 用户传入的 limit 参数 可能为 null
* @param limitOffset 用户传入的 offset 参数可能为 null
*/
StringBuilder process(StringBuilder sql, QueryWrapper queryWrapper, Integer limitRows, Integer limitOffset);
} }