001/*
002 *  Copyright (c) 2022-2023, 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;
017
018
019import java.util.EnumMap;
020import java.util.Map;
021import org.apache.ibatis.util.MapUtil;
022import com.mybatisflex.core.FlexGlobalConfig;
023import com.mybatisflex.core.dialect.impl.CommonsDialectImpl;
024import com.mybatisflex.core.dialect.impl.DB2105Dialect;
025import com.mybatisflex.core.dialect.impl.DmDialect;
026import com.mybatisflex.core.dialect.impl.OracleDialect;
027import com.mybatisflex.core.util.ObjectUtil;
028
029/**
030 * 方言工厂类,用于创建方言
031 */
032public class DialectFactory {
033
034    private DialectFactory() {
035    }
036
037    /**
038     * 数据库类型和方言的映射关系,可以通过其读取指定的方言,亦可能通过其扩展其他方言
039     * 比如,在 mybatis-flex 实现的方言中有 bug 或者 有自己的独立实现,可以添加自己的方言实现到
040     * 此 map 中,用于覆盖系统的方言实现
041     */
042    private static final Map<DbType, IDialect> dialectMap = new EnumMap<>(DbType.class);
043
044    /**
045     * 通过设置当前线程的数据库类型,以达到在代码执行时随时切换方言的功能
046     */
047    private static final ThreadLocal<DbType> dbTypeThreadLocal = new ThreadLocal<>();
048
049
050    /**
051     * 获取方言
052     *
053     * @return IDialect
054     */
055    public static IDialect getDialect() {
056        DbType dbType = ObjectUtil.requireNonNullElse(dbTypeThreadLocal.get(), FlexGlobalConfig.getDefaultConfig().getDbType());
057        return MapUtil.computeIfAbsent(dialectMap, dbType, DialectFactory::createDialect);
058    }
059
060    /**
061     * 设置当前线程的 dbType
062     *
063     * @param dbType
064     */
065    public static void setHintDbType(DbType dbType) {
066        dbTypeThreadLocal.set(dbType);
067    }
068
069    /**
070     * 获取当前线程的 dbType
071     *
072     * @return dbType
073     */
074    public static DbType getHintDbType() {
075        return dbTypeThreadLocal.get();
076    }
077
078
079    /**
080     * 清除当前线程的 dbType
081     */
082    public static void clearHintDbType() {
083        dbTypeThreadLocal.remove();
084    }
085
086
087    /**
088     * 可以为某个 dbType 注册(新增或覆盖)自己的方言
089     *
090     * @param dbType  数据库类型
091     * @param dialect 方言的实现
092     */
093    public static void registerDialect(DbType dbType, IDialect dialect) {
094        dialectMap.put(dbType, dialect);
095    }
096
097
098    private static IDialect createDialect(DbType dbType) {
099        switch (dbType) {
100            case MYSQL:
101            case H2:
102            case MARIADB:
103            case GBASE:
104            case OSCAR:
105            case XUGU:
106            case OCEAN_BASE:
107            case CUBRID:
108            case GOLDILOCKS:
109            case CSIIDB:
110            case HIVE:
111            case DORIS:
112                return new CommonsDialectImpl(KeywordWrap.BACK_QUOTE, LimitOffsetProcessor.MYSQL);
113            case CLICK_HOUSE:
114            case GBASE_8S:
115                return new CommonsDialectImpl(KeywordWrap.NONE, LimitOffsetProcessor.MYSQL);
116            case DM:
117                return new DmDialect();
118            case ORACLE:
119                return new OracleDialect();
120            case GAUSS:
121                return new CommonsDialectImpl(KeywordWrap.DOUBLE_QUOTATION, LimitOffsetProcessor.ORACLE);
122            case POSTGRE_SQL:
123            case SQLITE:
124            case HSQL:
125            case KINGBASE_ES:
126            case PHOENIX:
127            case SAP_HANA:
128            case IMPALA:
129            case HIGH_GO:
130            case VERTICA:
131            case REDSHIFT:
132            case OPENGAUSS:
133            case UXDB:
134            case LEALONE:
135                return new CommonsDialectImpl(KeywordWrap.DOUBLE_QUOTATION, LimitOffsetProcessor.POSTGRESQL);
136            case TDENGINE:
137                return new CommonsDialectImpl(KeywordWrap.BACK_QUOTE, LimitOffsetProcessor.POSTGRESQL);
138            case ORACLE_12C:
139                return new OracleDialect(LimitOffsetProcessor.DERBY);
140            case FIREBIRD:
141            case DB2:
142                return new CommonsDialectImpl(KeywordWrap.NONE, LimitOffsetProcessor.DERBY);
143            case DB2_1005:
144                return new DB2105Dialect(KeywordWrap.NONE, DB2105Dialect.DB2105LimitOffsetProcessor.DB2105);
145            case SQLSERVER:
146                return new CommonsDialectImpl(KeywordWrap.SQUARE_BRACKETS, LimitOffsetProcessor.SQLSERVER);
147            case SQLSERVER_2005:
148                return new CommonsDialectImpl(KeywordWrap.SQUARE_BRACKETS, LimitOffsetProcessor.SQLSERVER_2005);
149            case INFORMIX:
150                return new CommonsDialectImpl(KeywordWrap.NONE, LimitOffsetProcessor.INFORMIX);
151            case SINODB:
152                return new CommonsDialectImpl(KeywordWrap.DOUBLE_QUOTATION, LimitOffsetProcessor.SINODB);
153            case SYBASE:
154                return new CommonsDialectImpl(KeywordWrap.DOUBLE_QUOTATION, LimitOffsetProcessor.SYBASE);
155            default:
156                return new CommonsDialectImpl();
157        }
158    }
159
160}