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