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