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.exception.FlexExceptions;
020import com.mybatisflex.core.util.StringUtil;
021import org.apache.ibatis.datasource.unpooled.UnpooledDataSource;
022
023import javax.sql.DataSource;
024import java.lang.reflect.Method;
025import java.sql.Connection;
026import java.sql.SQLException;
027import java.util.regex.Pattern;
028
029/**
030 * DbType 解析 工具类
031 */
032public class DbTypeUtil {
033
034    private DbTypeUtil() {}
035
036    /**
037     * 获取当前配置的 DbType
038     */
039    public static DbType getDbType(DataSource dataSource) {
040        String jdbcUrl = getJdbcUrl(dataSource);
041
042        if (StringUtil.isNotBlank(jdbcUrl)) {
043            return parseDbType(jdbcUrl);
044        }
045
046        throw new IllegalStateException("Can not get dataSource jdbcUrl: " + dataSource.getClass().getName());
047    }
048
049    /**
050     * 通过数据源中获取 jdbc 的 url 配置
051     * 符合 HikariCP, druid, c3p0, DBCP, beecp 数据源框架 以及 MyBatis UnpooledDataSource 的获取规则
052     * UnpooledDataSource 参考 @{@link UnpooledDataSource#getUrl()}
053     *
054     * @return jdbc url 配置
055     */
056    public static String getJdbcUrl(DataSource dataSource) {
057        String[] methodNames = new String[]{"getUrl", "getJdbcUrl"};
058        for (String methodName : methodNames) {
059            try {
060                Method method = dataSource.getClass().getMethod(methodName);
061                return (String) method.invoke(dataSource);
062            } catch (Exception e) {
063                //ignore
064            }
065        }
066
067        Connection connection = null;
068        try {
069            connection = dataSource.getConnection();
070            return connection.getMetaData().getURL();
071        } catch (Exception e) {
072            throw FlexExceptions.wrap("Can not get the dataSource jdbcUrl", e);
073        } finally {
074            if (connection != null) {
075                try {
076                    connection.close();
077                } catch (SQLException e) { //ignore
078                }
079            }
080        }
081    }
082
083
084    /**
085     * 参考 druid  和 MyBatis-plus 的 JdbcUtils
086     * {@link com.alibaba.druid.util.JdbcUtils#getDbType(String, String)}
087     * {@link com.baomidou.mybatisplus.extension.toolkit.JdbcUtils#getDbType(String)}
088     *
089     * @param jdbcUrl jdbcURL
090     * @return 返回数据库类型
091     */
092    public static DbType parseDbType(String jdbcUrl) {
093        jdbcUrl = jdbcUrl.toLowerCase();
094        if (jdbcUrl.contains(":mysql:") || jdbcUrl.contains(":cobar:")) {
095            return DbType.MYSQL;
096        } else if (jdbcUrl.contains(":mariadb:")) {
097            return DbType.MARIADB;
098        } else if (jdbcUrl.contains(":oracle:")) {
099            return DbType.ORACLE;
100        } else if (jdbcUrl.contains(":sqlserver:") || jdbcUrl.contains(":microsoft:") || jdbcUrl.contains(":sqlserver2012:")) {
101            return DbType.SQLSERVER;
102        } else if (jdbcUrl.contains(":postgresql:")) {
103            return DbType.POSTGRE_SQL;
104        } else if (jdbcUrl.contains(":hsqldb:")) {
105            return DbType.HSQL;
106        } else if (jdbcUrl.contains(":db2:")) {
107            return DbType.DB2;
108        } else if (jdbcUrl.contains(":sqlite:")) {
109            return DbType.SQLITE;
110        } else if (jdbcUrl.contains(":h2:")) {
111            return DbType.H2;
112        } else if (isMatchedRegex(":dm\\d*:", jdbcUrl)) {
113            return DbType.DM;
114        } else if (jdbcUrl.contains(":xugu:")) {
115            return DbType.XUGU;
116        } else if (isMatchedRegex(":kingbase\\d*:", jdbcUrl)) {
117            return DbType.KINGBASE_ES;
118        } else if (jdbcUrl.contains(":phoenix:")) {
119            return DbType.PHOENIX;
120        } else if (jdbcUrl.contains(":zenith:")) {
121            return DbType.GAUSS;
122        } else if (jdbcUrl.contains(":gbase:")) {
123            return DbType.GBASE;
124        } else if (jdbcUrl.contains(":gbasedbt-sqli:") || jdbcUrl.contains(":informix-sqli:")) {
125            return DbType.GBASE_8S;
126        } else if (jdbcUrl.contains(":ch:") || jdbcUrl.contains(":clickhouse:")) {
127            return DbType.CLICK_HOUSE;
128        } else if (jdbcUrl.contains(":oscar:")) {
129            return DbType.OSCAR;
130        } else if (jdbcUrl.contains(":sybase:")) {
131            return DbType.SYBASE;
132        } else if (jdbcUrl.contains(":oceanbase:")) {
133            return DbType.OCEAN_BASE;
134        } else if (jdbcUrl.contains(":highgo:")) {
135            return DbType.HIGH_GO;
136        } else if (jdbcUrl.contains(":cubrid:")) {
137            return DbType.CUBRID;
138        } else if (jdbcUrl.contains(":goldilocks:")) {
139            return DbType.GOLDILOCKS;
140        } else if (jdbcUrl.contains(":csiidb:")) {
141            return DbType.CSIIDB;
142        } else if (jdbcUrl.contains(":sap:")) {
143            return DbType.SAP_HANA;
144        } else if (jdbcUrl.contains(":impala:")) {
145            return DbType.IMPALA;
146        } else if (jdbcUrl.contains(":vertica:")) {
147            return DbType.VERTICA;
148        } else if (jdbcUrl.contains(":xcloud:")) {
149            return DbType.XCloud;
150        } else if (jdbcUrl.contains(":firebirdsql:")) {
151            return DbType.FIREBIRD;
152        } else if (jdbcUrl.contains(":redshift:")) {
153            return DbType.REDSHIFT;
154        } else if (jdbcUrl.contains(":opengauss:")) {
155            return DbType.OPENGAUSS;
156        } else if (jdbcUrl.contains(":taos:") || jdbcUrl.contains(":taos-rs:")) {
157            return DbType.TDENGINE;
158        } else if (jdbcUrl.contains(":informix")) {
159            return DbType.INFORMIX;
160        } else if (jdbcUrl.contains(":uxdb:")) {
161            return DbType.UXDB;
162        } else if (jdbcUrl.contains(":greenplum:")) {
163            return DbType.GREENPLUM;
164        } else {
165            return DbType.OTHER;
166        }
167    }
168
169    /**
170     * 正则匹配,验证成功返回 true,验证失败返回 false
171     */
172    public static boolean isMatchedRegex(String regex, String jdbcUrl) {
173        if (null == jdbcUrl) {
174            return false;
175        }
176        return Pattern.compile(regex).matcher(jdbcUrl).find();
177    }
178}