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