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