001package com.mybatisflex.core.dialect.impl; 002 003import static com.mybatisflex.core.constant.FuncName.SUBSTRING; 004import static com.mybatisflex.core.constant.SqlConsts.DELIMITER; 005import static com.mybatisflex.core.constant.SqlConsts.NULLS_FIRST; 006import static com.mybatisflex.core.constant.SqlConsts.NULLS_LAST; 007import static com.mybatisflex.core.constant.SqlConsts.ORDER_BY; 008import java.util.List; 009import java.util.regex.Matcher; 010import java.util.regex.Pattern; 011import com.mybatisflex.core.dialect.KeywordWrap; 012import com.mybatisflex.core.dialect.LimitOffsetProcessor; 013import com.mybatisflex.core.query.CPI; 014import com.mybatisflex.core.query.QueryOrderBy; 015import com.mybatisflex.core.query.QueryTable; 016import com.mybatisflex.core.query.QueryWrapper; 017 018public class DB2105Dialect extends CommonsDialectImpl { 019 //TODO: 根据DatabaseMetaData获取数据库厂商名和版本号 020 public static final String DB2_1005_PRODUCT_VERSION = "1005"; 021 public static final String DB2_PRODUCT_NAME = "DB2"; 022 private static final Pattern ORDERBY_PATTERN = Pattern.compile("(\\S+)\\s+(\\S*)\\s*("+NULLS_FIRST.trim()+"|"+NULLS_LAST.trim()+")"); 023 private static final Pattern SUBSTRING_PATTERN = Pattern.compile("((?i)"+SUBSTRING.trim()+")(\\s*)(\\(.*?\\))"); 024 025 public DB2105Dialect(KeywordWrap keywordWrap, LimitOffsetProcessor limitOffsetProcessor) { 026 super(keywordWrap, limitOffsetProcessor); 027 } 028 029 @Override 030 public String buildSelectSql(QueryWrapper queryWrapper){ 031 String sql = super.buildSelectSql(queryWrapper); 032 if(sql!=null){ 033 Matcher matcher = SUBSTRING_PATTERN.matcher(sql); 034 sql = matcher.replaceAll("SUBSTR$2$3"); 035 } 036 return sql; 037 } 038 039 @Override 040 protected void buildOrderBySql(StringBuilder sqlBuilder, QueryWrapper queryWrapper, List<QueryTable> queryTables) { 041 List<QueryOrderBy> orderBys = CPI.getOrderBys(queryWrapper); 042 if (orderBys != null && !orderBys.isEmpty()) { 043 sqlBuilder.append(ORDER_BY); 044 int index = 0; 045 for (QueryOrderBy orderBy : orderBys) { 046 String orderBySql = orderBy.toSql(queryTables, this); 047 orderBySql = convertOrderBySqlForDB2105(orderBySql); // 转换SQL语句 048 sqlBuilder.append(orderBySql); 049 if (index != orderBys.size() - 1) { 050 sqlBuilder.append(DELIMITER); 051 } 052 index++; 053 } 054 } 055 } 056 057 private String convertOrderBySqlForDB2105(String sql) { 058 Matcher matcher = ORDERBY_PATTERN.matcher(sql); 059 if (matcher.find()) { 060 String column = matcher.group(1); 061 String orderType = matcher.group(2); 062 String nullOrder = matcher.group(3); 063 if (NULLS_FIRST.trim().equals(nullOrder)) { 064 sql = "CASE WHEN " + column + " IS NULL THEN 0 ELSE 1 END, " + column+" "+orderType; 065 } else if (NULLS_LAST.trim().equals(nullOrder)) { 066 sql = "CASE WHEN " + column + " IS NULL THEN 1 ELSE 0 END, " + column+" "+orderType; 067 } 068 } 069 return sql; 070 } 071 072 073 public interface DB2105LimitOffsetProcessor { 074 LimitOffsetProcessor DB2105 = (dialect, sql, queryWrapper, limitRows, limitOffset) -> { 075 StringBuilder limitSqlFragment = new StringBuilder( 076 "select * from ( select u_.*,rownumber() over() as rn from ( "); 077 limitSqlFragment.append(sql); 078 limitSqlFragment.append(" )u_ ) temp_ where temp_.rn between "); 079 080 if (limitRows != null && limitOffset != null) { 081 limitSqlFragment.append(limitOffset + 1); 082 limitSqlFragment.append(" and "); 083 limitSqlFragment.append(limitRows + limitOffset); 084 } else if (limitRows != null) { 085 limitSqlFragment.append("1 and "); 086 limitSqlFragment.append(limitRows); 087 } else { 088 return sql; 089 } 090 return limitSqlFragment; 091 }; 092 } 093}