From d020fe26b40943fcb8d1f69d799beb77ab2c2ab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=80=E6=BA=90=E6=B5=B7=E5=93=A5?= Date: Mon, 10 Jul 2023 14:46:47 +0800 Subject: [PATCH] feat: add sqlServer 2005 LimitOffsetProcessor --- .../core/dialect/LimitOffsetProcessor.java | 305 ++++++++++-------- .../core/dialect/impl/CommonsDialectImpl.java | 36 +-- 2 files changed, 181 insertions(+), 160 deletions(-) diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/dialect/LimitOffsetProcessor.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/dialect/LimitOffsetProcessor.java index 416d3c4c..2da59e72 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/dialect/LimitOffsetProcessor.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/dialect/LimitOffsetProcessor.java @@ -17,6 +17,7 @@ package com.mybatisflex.core.dialect; import com.mybatisflex.core.query.CPI; import com.mybatisflex.core.query.QueryOrderBy; +import com.mybatisflex.core.query.QueryTable; import com.mybatisflex.core.query.QueryWrapper; import com.mybatisflex.core.util.CollectionUtil; @@ -29,152 +30,172 @@ import static com.mybatisflex.core.constant.SqlConsts.*; */ public interface LimitOffsetProcessor { - /** - * MySql 的处理器 - * 适合 {@link DbType#MYSQL,DbType#MARIADB,DbType#H2,DbType#CLICK_HOUSE,DbType#XCloud} - */ - LimitOffsetProcessor MYSQL = (sql, queryWrapper, limitRows, limitOffset) -> { - if (limitRows != null && limitOffset != null) { - sql.append(LIMIT).append(limitOffset).append(DELIMITER).append(limitRows); - } else if (limitRows != null) { - sql.append(LIMIT).append(limitRows); - } - return sql; - }; - - /** - * Postgresql 的处理器 - * 适合 {@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#OPENGAUSS,DbType#TDENGINE,DbType#UXDB} - */ - LimitOffsetProcessor POSTGRESQL = (sql, queryWrapper, limitRows, limitOffset) -> { - if (limitRows != null && limitOffset != null) { - sql.append(LIMIT).append(limitRows).append(OFFSET).append(limitOffset); - } else if (limitRows != null) { - sql.append(LIMIT).append(limitRows); - } - return sql; - }; - - /** - * derby 的处理器 - * 适合 {@link DbType#DERBY,DbType#ORACLE_12C,DbType#SQLSERVER ,DbType#POSTGRE_SQL} - */ - LimitOffsetProcessor DERBY = (sql, queryWrapper, limitRows, limitOffset) -> { - if (limitRows != null && limitOffset != null) { - // OFFSET ** ROWS FETCH NEXT ** ROWS ONLY") - sql.append(OFFSET).append(limitOffset).append(ROWS_FETCH_NEXT).append(limitRows).append(ROWS_ONLY); - } else if (limitRows != null) { - sql.append(OFFSET).append(0).append(ROWS_FETCH_NEXT).append(limitRows).append(ROWS_ONLY); - } - return sql; - }; - - /** - * derby 的处理器 - * 适合 {@link DbType#DERBY,DbType#ORACLE_12C,DbType#SQLSERVER ,DbType#POSTGRE_SQL} - */ - LimitOffsetProcessor SQLSERVER = (sql, queryWrapper, limitRows, limitOffset) -> { - if (limitRows != null && limitOffset != null) { - // OFFSET ** ROWS FETCH NEXT ** ROWS ONLY") - sql.append(OFFSET).append(limitOffset).append(ROWS_FETCH_NEXT).append(limitRows).append(ROWS_ONLY); - } else if (limitRows != null) { - List orderBys = CPI.getOrderBys(queryWrapper); - if (CollectionUtil.isNotEmpty(orderBys)) { - sql.append(OFFSET).append(0).append(ROWS_FETCH_NEXT).append(limitRows).append(ROWS_ONLY); - } else { - sql.insert(6, TOP + limitRows); - } - } - return sql; - }; + /** + * 处理构建 limit 和 offset + * + * @param dialect 数据方言 + * @param sql 已经构建的 sql + * @param queryWrapper 参数内容 + * @param limitRows 用户传入的 limit 参数 可能为 null + * @param limitOffset 用户传入的 offset 参数,可能为 null + */ + StringBuilder process(IDialect dialect, StringBuilder sql, QueryWrapper queryWrapper, Integer limitRows, Integer limitOffset); - /** - * SqlServer 2005 limit 处理器 - */ - LimitOffsetProcessor SQLSERVER_2005 = (sql, queryWrapper, limitRows, limitOffset) -> { - if (limitRows != null) { - if (limitOffset == null) { - limitOffset = 0; - } - StringBuilder newSql = new StringBuilder("SELECT * FROM (SELECT TEMP_DATAS.*, ROW_NUMBER() OVER() AS RN FROM ("); - newSql.append(sql).append(") AS TEMP_DATAS) WHERE RN > ").append(limitOffset).append(" AND RN <= ").append(limitRows + limitRows); - return newSql; - } - return sql; - }; + /** + * MySql 的处理器 + * 适合 {@link DbType#MYSQL,DbType#MARIADB,DbType#H2,DbType#CLICK_HOUSE,DbType#XCloud} + */ + LimitOffsetProcessor MYSQL = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { + if (limitRows != null && limitOffset != null) { + sql.append(LIMIT).append(limitOffset).append(DELIMITER).append(limitRows); + } else if (limitRows != null) { + sql.append(LIMIT).append(limitRows); + } + return sql; + }; + + /** + * Postgresql 的处理器 + * 适合 {@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#OPENGAUSS,DbType#TDENGINE,DbType#UXDB} + */ + LimitOffsetProcessor POSTGRESQL = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { + if (limitRows != null && limitOffset != null) { + sql.append(LIMIT).append(limitRows).append(OFFSET).append(limitOffset); + } else if (limitRows != null) { + sql.append(LIMIT).append(limitRows); + } + return sql; + }; + + /** + * derby 的处理器 + * 适合 {@link DbType#DERBY,DbType#ORACLE_12C,DbType#SQLSERVER ,DbType#POSTGRE_SQL} + */ + LimitOffsetProcessor DERBY = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { + if (limitRows != null && limitOffset != null) { + // OFFSET ** ROWS FETCH NEXT ** ROWS ONLY") + sql.append(OFFSET).append(limitOffset).append(ROWS_FETCH_NEXT).append(limitRows).append(ROWS_ONLY); + } else if (limitRows != null) { + sql.append(OFFSET).append(0).append(ROWS_FETCH_NEXT).append(limitRows).append(ROWS_ONLY); + } + return sql; + }; + + /** + * derby 的处理器 + * 适合 {@link DbType#DERBY,DbType#ORACLE_12C,DbType#SQLSERVER ,DbType#POSTGRE_SQL} + */ + LimitOffsetProcessor SQLSERVER = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { + if (limitRows != null && limitOffset != null) { + // OFFSET ** ROWS FETCH NEXT ** ROWS ONLY") + sql.append(OFFSET).append(limitOffset).append(ROWS_FETCH_NEXT).append(limitRows).append(ROWS_ONLY); + } else if (limitRows != null) { + List orderBys = CPI.getOrderBys(queryWrapper); + if (CollectionUtil.isNotEmpty(orderBys)) { + sql.append(OFFSET).append(0).append(ROWS_FETCH_NEXT).append(limitRows).append(ROWS_ONLY); + } else { + sql.insert(6, TOP + limitRows); + } + } + return sql; + }; - /** - * Informix 的处理器 - * 适合 {@link DbType#INFORMIX} - * 文档 {@link https://www.ibm.com/docs/en/informix-servers/14.10?topic=clause-restricting-return-values-skip-limit-first-options} - */ - LimitOffsetProcessor INFORMIX = (sql, queryWrapper, limitRows, limitOffset) -> { - if (limitRows != null && limitOffset != null) { - // SELECT SKIP 2 FIRST 1 * FROM - 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; - }; + /** + * SqlServer 2005 limit 处理器 + */ + LimitOffsetProcessor SQLSERVER_2005 = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { + if (limitRows != null) { + if (limitOffset == null) { + limitOffset = 0; + } + String orderByString; + List orderBys = CPI.getOrderBys(queryWrapper); + if (orderBys == null || orderBys.isEmpty()) { + orderByString = "ORDER BY CURRENT_TIMESTAMP"; + } else { + StringBuilder orderBySql = new StringBuilder(ORDER_BY); + int index = 0; + List queryTables = CPI.getQueryTables(queryWrapper); + for (QueryOrderBy orderBy : orderBys) { + orderBySql.append(orderBy.toSql(queryTables, dialect)); + if (index != orderBys.size() - 1) { + orderBySql.append(DELIMITER); + } + index++; + } + orderByString = orderBySql.toString(); + } + StringBuilder newSql = new StringBuilder("SELECT * FROM (SELECT TEMP_DATAS.*, ROW_NUMBER() OVER(").append(orderByString).append(") AS RN FROM ("); + newSql.append(sql).append(") AS TEMP_DATAS) WHERE RN > ").append(limitOffset).append(" AND RN <= ").append(limitRows + limitRows); + return newSql; + } + return sql; + }; + + + /** + * Informix 的处理器 + * 适合 {@link DbType#INFORMIX} + * 文档 {@link https://www.ibm.com/docs/en/informix-servers/14.10?topic=clause-restricting-return-values-skip-limit-first-options} + */ + LimitOffsetProcessor INFORMIX = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { + if (limitRows != null && limitOffset != null) { + // SELECT SKIP 2 FIRST 1 * FROM + sql.insert(6, SKIP + limitOffset + FIRST + limitRows); + } else if (limitRows != null) { + sql.insert(6, FIRST + limitRows); + } + return sql; + }; + + /** + * Firebird 的处理器 + * 适合 {@link DbType#FIREBIRD} + */ + LimitOffsetProcessor FIREBIRD = (dialect, 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 = (dialect, 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 = (dialect, 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); } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/dialect/impl/CommonsDialectImpl.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/dialect/impl/CommonsDialectImpl.java index 2039f28a..818366a5 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/dialect/impl/CommonsDialectImpl.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/dialect/impl/CommonsDialectImpl.java @@ -128,8 +128,8 @@ public class CommonsDialectImpl implements IDialect { } sql.append(wrap(getRealTable(tableName))); sql.append(BLANK).append(BRACKET_LEFT) - .append(fields) - .append(BRACKET_RIGHT).append(BLANK); + .append(fields) + .append(BRACKET_RIGHT).append(BLANK); sql.append(VALUES).append(questions); return sql.toString(); } @@ -341,12 +341,12 @@ public class CommonsDialectImpl implements IDialect { //用户未配置别名的情况下,自动未用户添加别名 if (selectColumnTable != null - && selectColumnName != null - && !"*".equals(selectColumnName) - && StringUtil.isBlank(selectColumn.getAlias()) - && !(selectColumnTable instanceof SelectQueryTable) - && !CPI.isSameTable(firstTable, selectColumnTable) - && ArrayUtil.contains(firstTableColumns, selectColumnName) + && selectColumnName != null + && !"*".equals(selectColumnName) + && StringUtil.isBlank(selectColumn.getAlias()) + && !(selectColumnTable instanceof SelectQueryTable) + && !CPI.isSameTable(firstTable, selectColumnTable) + && ArrayUtil.contains(firstTableColumns, selectColumnName) ) { QueryColumn newSelectColumn = selectColumn.as(selectColumnTable.getName() + "$" + selectColumnName); selectColumns.set(i, newSelectColumn); @@ -514,9 +514,9 @@ public class CommonsDialectImpl implements IDialect { } return sql.append(BRACKET_LEFT).append(sqlFields).append(BRACKET_RIGHT) - .append(VALUES) - .append(BRACKET_LEFT).append(sqlValues).append(BRACKET_RIGHT) - .toString(); + .append(VALUES) + .append(BRACKET_LEFT).append(sqlValues).append(BRACKET_RIGHT) + .toString(); } @@ -542,9 +542,9 @@ public class CommonsDialectImpl implements IDialect { } return sql.append(BRACKET_LEFT).append(sqlFields).append(BRACKET_RIGHT) - .append(VALUES) - .append(BRACKET_LEFT).append(sqlValues).append(BRACKET_RIGHT) - .toString(); + .append(VALUES) + .append(BRACKET_LEFT).append(sqlValues).append(BRACKET_RIGHT) + .toString(); } @@ -558,8 +558,8 @@ public class CommonsDialectImpl implements IDialect { warpedInsertColumns[i] = wrap(insertColumns[i]); } sql.append(BRACKET_LEFT) - .append(StringUtil.join(DELIMITER, warpedInsertColumns)) - .append(BRACKET_RIGHT); + .append(StringUtil.join(DELIMITER, warpedInsertColumns)) + .append(BRACKET_RIGHT); sql.append(VALUES); Map onInsertColumns = tableInfo.getOnInsertColumns(); @@ -782,7 +782,7 @@ public class CommonsDialectImpl implements IDialect { Map rawValueMap = tableInfo.obtainUpdateRawValueMap(entity); sql.append(UPDATE).append(forHint(CPI.getHint(queryWrapper))) - .append(tableInfo.getWrapSchemaAndTableName(this)).append(SET); + .append(tableInfo.getWrapSchemaAndTableName(this)).append(SET); StringJoiner stringJoiner = new StringJoiner(DELIMITER); @@ -1051,7 +1051,7 @@ public class CommonsDialectImpl implements IDialect { * 构建 limit 和 offset 的参数 */ protected StringBuilder buildLimitOffsetSql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, Integer limitRows, Integer limitOffset) { - return limitOffsetProcessor.process(sqlBuilder, queryWrapper, limitRows, limitOffset); + return limitOffsetProcessor.process(this, sqlBuilder, queryWrapper, limitRows, limitOffset); }