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}