美文网首页
达梦数据库兼容问题

达梦数据库兼容问题

作者: pilisiyang | 来源:发表于2020-10-12 14:53 被阅读0次

    项目背景

    项目需要适配国产数据库,以下是适配达梦数据库时遇到的一些问题

    配置达梦数据库

    通过引入Dm8JdbcDriver18依赖配置数据库driver-class,配置数据库连接信息后,mybatis能进行crud操作,但是某些特殊属性及函数是无法使用的,例如 domain,link等。
    依赖:

            <dependency>
                <groupId>com.dameng</groupId>
                <artifactId>Dm8JdbcDriver18</artifactId>
                <version>8.1.1.49</version>
            </dependency>
    

    配置:

        driver-class-name: dm.jdbc.driver.DmDriver
        url: jdbc:dm://xxxx:x/xx
        username: xx
        password: xx
        type: com.alibaba.druid.pool.DruidDataSource
    
    a'a.png

    Flowable集成达梦数据库的使用时遇到的问题

    • 自动加载数据源时,无法识别DM数据库类型,采用覆盖源码,设置成MySQL或者Oracle的数据库类型

    覆盖org.flowable.common.engine.impl.AbstractEngineConfiguration
    修改getDefaultDatabaseTypeMappings,新增达梦数据库类型
    databaseTypeMappings.setProperty("DM DBMS", DATABASE_TYPE_ORACLE);

    • 自动创建act和flw开头的表,需要将初始化语句修改,手动执行;或者将MySQL或Oracle数据表初始化后,手动导入DM数据库,达梦数据库提供了数据迁移工具


      QQ截图20201012143349.png
    • 执行过程中遇到数据类型不匹配的问题,例如程序启动时,flowable会通过Liquibase去修改FLW_EV_DATABASECHANGELOGLOCK表数据,由于DM无法转换true/false报错

    报错信息:

    Caused by: liquibase.exception.DatabaseException: Error executing SQL UPDATE FLW_EV_DATABASECHANGELOGLOCK SET LOCKED = TRUE, LOCKEDBY = 'LAPTOP-RO0A74NR (192.168.6.154)', LOCKGRANTED = '2020-08-06 17:06:10.275' WHERE ID = 1 AND LOCKED = FALSE: 第1 行附近出现错误: 数据类型不匹配

    第一步需要创建新的class,继承AbstractJdbcDatabase,并且放在liquibase.database.core包下,这样Liquibase才会识别DM DBMS类型,这里是仿照OracleDatabase的做的

    package liquibase.database.core;
    
    import liquibase.CatalogAndSchema;
    import liquibase.Scope;
    import liquibase.database.AbstractJdbcDatabase;
    import liquibase.database.DatabaseConnection;
    import liquibase.database.OfflineConnection;
    import liquibase.database.jvm.JdbcConnection;
    import liquibase.exception.DatabaseException;
    import liquibase.exception.UnexpectedLiquibaseException;
    import liquibase.exception.ValidationErrors;
    import liquibase.executor.ExecutorService;
    import liquibase.logging.LogService;
    import liquibase.logging.LogType;
    import liquibase.statement.DatabaseFunction;
    import liquibase.statement.SequenceCurrentValueFunction;
    import liquibase.statement.SequenceNextValueFunction;
    import liquibase.statement.core.RawCallStatement;
    import liquibase.statement.core.RawSqlStatement;
    import liquibase.structure.DatabaseObject;
    import liquibase.structure.core.Catalog;
    import liquibase.structure.core.Index;
    import liquibase.structure.core.PrimaryKey;
    import liquibase.structure.core.Schema;
    import liquibase.util.JdbcUtils;
    import liquibase.util.StringUtils;
    
    import java.lang.reflect.Method;
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Locale;
    import java.util.Map;
    import java.util.Properties;
    import java.util.ResourceBundle;
    import java.util.Set;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    import static java.util.ResourceBundle.getBundle;
    
    /**
     * Encapsulates Oracle database support.
     */
    public class DmDatabase extends AbstractJdbcDatabase {
        private static final Pattern PROXY_USER = Pattern.compile(".*(?:thin|oci)\\:(.+)/@.*");
    
        public static final String PRODUCT_NAME = "DM DBMS";
        private static ResourceBundle coreBundle = getBundle("liquibase/i18n/liquibase-core");
        protected final int SHORT_IDENTIFIERS_LENGTH = 30;
        protected final int LONG_IDENTIFIERS_LEGNTH = 128;
        public static final int ORACLE_12C_MAJOR_VERSION = 12;
    
        private Set<String> reservedWords = new HashSet<>();
        private Set<String> userDefinedTypes;
        private Map<String, String> savedSessionNlsSettings;
    
        private Boolean canAccessDbaRecycleBin;
        private Integer databaseMajorVersion;
        private Integer databaseMinorVersion;
    
        /**
         * Default constructor for an object that represents the Oracle Database DBMS.
         */
        public DmDatabase() {
            super.unquotedObjectsAreUppercased = true;
            //noinspection HardCodedStringLiteral
            super.setCurrentDateTimeFunction("SYSTIMESTAMP");
            // Setting list of Oracle's native functions
            //noinspection HardCodedStringLiteral
            dateFunctions.add(new DatabaseFunction("SYSDATE"));
            //noinspection HardCodedStringLiteral
            dateFunctions.add(new DatabaseFunction("SYSTIMESTAMP"));
            //noinspection HardCodedStringLiteral
            dateFunctions.add(new DatabaseFunction("CURRENT_TIMESTAMP"));
            //noinspection HardCodedStringLiteral
            super.sequenceNextValueFunction = "%s.nextval";
            //noinspection HardCodedStringLiteral
            super.sequenceCurrentValueFunction = "%s.currval";
        }
    
        @Override
        public int getPriority() {
            return PRIORITY_DEFAULT;
        }
    
        private final void tryProxySessionn(final String url, final Connection con) {
            Matcher m = PROXY_USER.matcher(url);
            if (m.matches()) {
                Properties props = new Properties();
                props.put("PROXY_USER_NAME", m.group(1));
                try {
                    Method method = con.getClass().getMethod("openProxySession", int.class, Properties.class);
                    method.setAccessible(true);
                    method.invoke(con, 1, props);
                } catch (Exception e) {
                    Scope.getCurrentScope().getLog(getClass()).info(LogType.LOG, "Could not open proxy session on OracleDatabase: " + e.getCause().getMessage());
                }
            }
        }
    
        @Override
        public void setConnection(DatabaseConnection conn) {
            //noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,
            // HardCodedStringLiteral
            //noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,
            // HardCodedStringLiteral
            reservedWords.addAll(Arrays.asList("GROUP", "USER", "SESSION", "PASSWORD", "RESOURCE", "START", "SIZE", "UID", "DESC", "ORDER")); //more reserved words not returned by driver
    
            Connection sqlConn = null;
            if (!(conn instanceof OfflineConnection)) {
                try {
                    /*
                     * Don't try to call getWrappedConnection if the conn instance is
                     * is not a JdbcConnection. This happens for OfflineConnection.
                     * see https://liquibase.jira.com/browse/CORE-2192
                     */
                    if (conn instanceof JdbcConnection) {
                        sqlConn = ((JdbcConnection) conn).getWrappedConnection();
                    }
                } catch (Exception e) {
                    throw new UnexpectedLiquibaseException(e);
                }
    
                if (sqlConn != null) {
                    tryProxySessionn(conn.getURL(), sqlConn);
    
                    try {
                        //noinspection HardCodedStringLiteral
                        reservedWords.addAll(Arrays.asList(sqlConn.getMetaData().getSQLKeywords().toUpperCase().split(",\\s*")));
                    } catch (SQLException e) {
                        //noinspection HardCodedStringLiteral
                        LogService.getLog(getClass()).info(LogType.LOG, "Could get sql keywords on OracleDatabase: " + e.getMessage());
                        //can not get keywords. Continue on
                    }
                    try {
                        Method method = sqlConn.getClass().getMethod("setRemarksReporting", Boolean.TYPE);
                        method.setAccessible(true);
                        method.invoke(sqlConn, true);
                    } catch (Exception e) {
                        //noinspection HardCodedStringLiteral
                        LogService.getLog(getClass()).info(LogType.LOG, "Could not set remarks reporting on OracleDatabase: " + e.getMessage());
    
                        //cannot set it. That is OK
                    }
    
                    Statement statement = null;
                    ResultSet resultSet = null;
                    try {
                        statement = sqlConn.createStatement();
                        //noinspection HardCodedStringLiteral
                        resultSet = statement.executeQuery("SELECT value FROM v$parameter WHERE name = 'compatible'");
                        String compatibleVersion = null;
                        if (resultSet.next()) {
                            //noinspection HardCodedStringLiteral
                            compatibleVersion = resultSet.getString("value");
                        }
                        if (compatibleVersion != null) {
                            Matcher majorVersionMatcher = Pattern.compile("(\\d+)\\.(\\d+)\\..*").matcher(compatibleVersion);
                            if (majorVersionMatcher.matches()) {
                                this.databaseMajorVersion = Integer.valueOf(majorVersionMatcher.group(1));
                                this.databaseMinorVersion = Integer.valueOf(majorVersionMatcher.group(2));
                            }
                        }
                    } catch (SQLException e) {
                        @SuppressWarnings("HardCodedStringLiteral") String message = "Cannot read from v$parameter: " + e.getMessage();
    
                        //noinspection HardCodedStringLiteral
                        LogService.getLog(getClass()).info(LogType.LOG, "Could not set check compatibility mode on OracleDatabase, assuming not running in any sort of compatibility mode: " + message);
                    } finally {
                        JdbcUtils.close(resultSet, statement);
                    }
    
    
                }
            }
            super.setConnection(conn);
        }
    
        @Override
        public String getShortName() {
            //noinspection HardCodedStringLiteral
            return "dm";
        }
    
        @Override
        protected String getDefaultDatabaseProductName() {
            //noinspection HardCodedStringLiteral
            return "dm";
        }
    
        @Override
        public int getDatabaseMajorVersion() throws DatabaseException {
            if (databaseMajorVersion == null) {
                return super.getDatabaseMajorVersion();
            } else {
                return databaseMajorVersion;
            }
        }
    
        @Override
        public int getDatabaseMinorVersion() throws DatabaseException {
            if (databaseMinorVersion == null) {
                return super.getDatabaseMinorVersion();
            } else {
                return databaseMinorVersion;
            }
        }
    
        @Override
        public Integer getDefaultPort() {
            return 5236;
        }
    
        @Override
        public String getJdbcCatalogName(CatalogAndSchema schema) {
            return null;
        }
    
        @Override
        public String getJdbcSchemaName(CatalogAndSchema schema) {
            return correctObjectName((schema.getCatalogName() == null) ? schema.getSchemaName() : schema.getCatalogName(), Schema.class);
        }
    
        @Override
        protected String getAutoIncrementClause(final String generationType, final Boolean defaultOnNull) {
            if (StringUtils.isEmpty(generationType)) {
                return "";
            }
    
            String autoIncrementClause = "GENERATED %s AS IDENTITY"; // %s -- [ ALWAYS | BY DEFAULT [ ON NULL ] ]
            String generationStrategy = generationType;
            if (Boolean.TRUE.equals(defaultOnNull) && generationType.toUpperCase().equals("BY DEFAULT")) {
                generationStrategy += " ON NULL";
            }
            return String.format(autoIncrementClause, generationStrategy);
        }
    
        @Override
        public String generatePrimaryKeyName(String tableName) {
            if (tableName.length() > 27) {
                //noinspection HardCodedStringLiteral
                return "PK_" + tableName.toUpperCase(Locale.US).substring(0, 27);
            } else {
                //noinspection HardCodedStringLiteral
                return "PK_" + tableName.toUpperCase(Locale.US);
            }
        }
    
        @Override
        public boolean supportsInitiallyDeferrableColumns() {
            return true;
        }
    
        @Override
        public boolean isReservedWord(String objectName) {
            return reservedWords.contains(objectName.toUpperCase());
        }
    
        @Override
        public boolean supportsSequences() {
            return true;
        }
    
        /**
         * Oracle supports catalogs in liquibase terms
         *
         * @return false
         */
        @Override
        public boolean supportsSchemas() {
            return false;
        }
    
        @Override
        protected String getConnectionCatalogName() throws DatabaseException {
            if (getConnection() instanceof OfflineConnection) {
                return getConnection().getCatalog();
            }
            try {
                //noinspection HardCodedStringLiteral
                return ExecutorService.getInstance().getExecutor(this).queryForObject(new RawCallStatement("select sys_context( 'userenv', 'current_schema' ) from dual"), String.class);
            } catch (Exception e) {
                //noinspection HardCodedStringLiteral
                LogService.getLog(getClass()).info(LogType.LOG, "Error getting default schema", e);
            }
            return null;
        }
    
        @Override
        public boolean isCorrectDatabaseImplementation(DatabaseConnection conn) throws DatabaseException {
            return PRODUCT_NAME.equalsIgnoreCase(conn.getDatabaseProductName());
        }
    
        @Override
        public String getDefaultDriver(String url) {
            //noinspection HardCodedStringLiteral
            if (url.startsWith("jdbc:dm")) {
                return "dm.jdbc.driver.DmDriver";
            }
            return null;
        }
    
        @Override
        public String getDefaultCatalogName() {//NOPMD
            return (super.getDefaultCatalogName() == null) ? null : super.getDefaultCatalogName().toUpperCase(Locale.US);
        }
    
        /**
         * <p>Returns an Oracle date literal with the same value as a string formatted using ISO 8601.</p>
         *
         * <p>Convert an ISO8601 date string to one of the following results:
         * to_date('1995-05-23', 'YYYY-MM-DD')
         * to_date('1995-05-23 09:23:59', 'YYYY-MM-DD HH24:MI:SS')</p>
         * <p>
         * Implementation restriction:<br>
         * Currently, only the following subsets of ISO8601 are supported:<br>
         * <ul>
         * <li>YYYY-MM-DD</li>
         * <li>YYYY-MM-DDThh:mm:ss</li>
         * </ul>
         */
        @Override
        public String getDateLiteral(String isoDate) {
            String normalLiteral = super.getDateLiteral(isoDate);
    
            if (isDateOnly(isoDate)) {
                StringBuffer val = new StringBuffer();
                //noinspection HardCodedStringLiteral
                val.append("TO_DATE(");
                val.append(normalLiteral);
                //noinspection HardCodedStringLiteral
                val.append(", 'YYYY-MM-DD')");
                return val.toString();
            } else if (isTimeOnly(isoDate)) {
                StringBuffer val = new StringBuffer();
                //noinspection HardCodedStringLiteral
                val.append("TO_DATE(");
                val.append(normalLiteral);
                //noinspection HardCodedStringLiteral
                val.append(", 'HH24:MI:SS')");
                return val.toString();
            } else if (isTimestamp(isoDate)) {
                StringBuffer val = new StringBuffer(26);
                //noinspection HardCodedStringLiteral
                val.append("TO_TIMESTAMP(");
                val.append(normalLiteral);
                //noinspection HardCodedStringLiteral
                val.append(", 'YYYY-MM-DD HH24:MI:SS.FF')");
                return val.toString();
            } else if (isDateTime(isoDate)) {
                int seppos = normalLiteral.lastIndexOf('.');
                if (seppos != -1) {
                    normalLiteral = normalLiteral.substring(0, seppos) + "'";
                }
                StringBuffer val = new StringBuffer(26);
                //noinspection HardCodedStringLiteral
                val.append("TO_DATE(");
                val.append(normalLiteral);
                //noinspection HardCodedStringLiteral
                val.append(", 'YYYY-MM-DD HH24:MI:SS')");
                return val.toString();
            }
            //noinspection HardCodedStringLiteral
            return "UNSUPPORTED:" + isoDate;
        }
    
        @Override
        public boolean isSystemObject(DatabaseObject example) {
            if (example == null) {
                return false;
            }
    
            if (this.isLiquibaseObject(example)) {
                return false;
            }
    
            if (example instanceof Schema) {
                //noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral
                if ("SYSTEM".equals(example.getName()) || "SYS".equals(example.getName()) || "CTXSYS".equals(example.getName()) || "XDB".equals(example.getName())) {
                    return true;
                }
                //noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral
                if ("SYSTEM".equals(example.getSchema().getCatalogName()) || "SYS".equals(example.getSchema().getCatalogName()) || "CTXSYS".equals(example.getSchema().getCatalogName()) || "XDB".equals(example.getSchema().getCatalogName())) {
                    return true;
                }
            } else if (isSystemObject(example.getSchema())) {
                return true;
            }
            if (example instanceof Catalog) {
                //noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral
                if (("SYSTEM".equals(example.getName()) || "SYS".equals(example.getName()) || "CTXSYS".equals(example.getName()) || "XDB".equals(example.getName()))) {
                    return true;
                }
            } else if (example.getName() != null) {
                //noinspection HardCodedStringLiteral
                if (example.getName().startsWith("BIN$")) { //oracle deleted table
                    boolean filteredInOriginalQuery = this.canAccessDbaRecycleBin();
                    if (!filteredInOriginalQuery) {
                        filteredInOriginalQuery = StringUtils.trimToEmpty(example.getSchema().getName()).equalsIgnoreCase(this.getConnection().getConnectionUserName());
                    }
    
                    if (filteredInOriginalQuery) {
                        return !((example instanceof PrimaryKey) || (example instanceof Index) || (example instanceof
                                liquibase.statement.UniqueConstraint));
                    } else {
                        return true;
                    }
                } else //noinspection HardCodedStringLiteral
                    if (example.getName().startsWith("AQ$")) { //oracle AQ tables
                        return true;
                    } else //noinspection HardCodedStringLiteral
                        if (example.getName().startsWith("DR$")) { //oracle index tables
                            return true;
                        } else //noinspection HardCodedStringLiteral
                            if (example.getName().startsWith("SYS_IOT_OVER")) { //oracle system table
                                return true;
                            } else //noinspection HardCodedStringLiteral,HardCodedStringLiteral
                                if ((example.getName().startsWith("MDRT_") || example.getName().startsWith("MDRS_")) && example.getName().endsWith("$")) {
                                    // CORE-1768 - Oracle creates these for spatial indices and will remove them when the index is removed.
                                    return true;
                                } else //noinspection HardCodedStringLiteral
                                    if (example.getName().startsWith("MLOG$_")) { //Created by materliaized view logs for every table that is part of a materialized view. Not available for DDL operations.
                                        return true;
                                    } else //noinspection HardCodedStringLiteral
                                        if (example.getName().startsWith("RUPD$_")) { //Created by materialized view log tables using primary keys. Not available for DDL operations.
                                            return true;
                                        } else //noinspection HardCodedStringLiteral
                                            if (example.getName().startsWith("WM$_")) { //Workspace Manager backup tables.
                                                return true;
                                            } else //noinspection HardCodedStringLiteral
                                                if ("CREATE$JAVA$LOB$TABLE".equals(example.getName())) { //This table contains the name of the Java object, the date it was loaded, and has a BLOB column to store the Java object.
                                                    return true;
                                                } else //noinspection HardCodedStringLiteral
                                                    if ("JAVA$CLASS$MD5$TABLE".equals(example.getName())) { //This is a hash table that tracks the loading of Java objects into a schema.
                                                        return true;
                                                    } else //noinspection HardCodedStringLiteral
                                                        if (example.getName().startsWith("ISEQ$$_")) { //System-generated sequence
                                                            return true;
                                                        } else //noinspection HardCodedStringLiteral
                                                            if (example.getName().startsWith("USLOG$")) { //for update materialized view
                                                                return true;
                                                            } else if (example.getName().startsWith("SYS_FBA")) { //for Flashback tables
                                                                return true;
                                                            }
            }
    
            return super.isSystemObject(example);
        }
    
        @Override
        public boolean supportsTablespaces() {
            return true;
        }
    
        @Override
        public boolean supportsAutoIncrement() {
            // Oracle supports Identity beginning with version 12c
            boolean isAutoIncrementSupported = false;
    
            try {
                if (getDatabaseMajorVersion() >= 12) {
                    isAutoIncrementSupported = true;
                }
    
                // Returning true will generate create table command with 'IDENTITY' clause, example:
                // CREATE TABLE AutoIncTest (IDPrimaryKey NUMBER(19) GENERATED BY DEFAULT AS IDENTITY NOT NULL, TypeID NUMBER(3) NOT NULL, Description NVARCHAR2(50), CONSTRAINT PK_AutoIncTest PRIMARY KEY (IDPrimaryKey));
    
                // While returning false will continue to generate create table command without 'IDENTITY' clause, example:
                // CREATE TABLE AutoIncTest (IDPrimaryKey NUMBER(19) NOT NULL, TypeID NUMBER(3) NOT NULL, Description NVARCHAR2(50), CONSTRAINT PK_AutoIncTest PRIMARY KEY (IDPrimaryKey));
    
            } catch (DatabaseException ex) {
                isAutoIncrementSupported = false;
            }
    
            return isAutoIncrementSupported;
        }
    
    
    //    public Set<UniqueConstraint> findUniqueConstraints(String schema) throws DatabaseException {
    //        Set<UniqueConstraint> returnSet = new HashSet<UniqueConstraint>();
    //
    //        List<Map> maps = new Executor(this).queryForList(new RawSqlStatement("SELECT UC.CONSTRAINT_NAME, UCC.TABLE_NAME, UCC.COLUMN_NAME FROM USER_CONSTRAINTS UC, USER_CONS_COLUMNS UCC WHERE UC.CONSTRAINT_NAME=UCC.CONSTRAINT_NAME AND CONSTRAINT_TYPE='U' ORDER BY UC.CONSTRAINT_NAME"));
    //
    //        UniqueConstraint constraint = null;
    //        for (Map map : maps) {
    //            if (constraint == null || !constraint.getName().equals(constraint.getName())) {
    //                returnSet.add(constraint);
    //                Table table = new Table((String) map.get("TABLE_NAME"));
    //                constraint = new UniqueConstraint(map.get("CONSTRAINT_NAME").toString(), table);
    //            }
    //        }
    //        if (constraint != null) {
    //            returnSet.add(constraint);
    //        }
    //
    //        return returnSet;
    //    }
    
        @Override
        public boolean supportsRestrictForeignKeys() {
            return false;
        }
    
        @Override
        public int getDataTypeMaxParameters(String dataTypeName) {
            //noinspection HardCodedStringLiteral
            if ("BINARY_FLOAT".equals(dataTypeName.toUpperCase())) {
                return 0;
            }
            //noinspection HardCodedStringLiteral
            if ("BINARY_DOUBLE".equals(dataTypeName.toUpperCase())) {
                return 0;
            }
            return super.getDataTypeMaxParameters(dataTypeName);
        }
    
        public String getSystemTableWhereClause(String tableNameColumn) {
            List<String> clauses = new ArrayList<String>(Arrays.asList("BIN$",
                    "AQ$",
                    "DR$",
                    "SYS_IOT_OVER",
                    "MLOG$_",
                    "RUPD$_",
                    "WM$_",
                    "ISEQ$$_",
                    "USLOG$",
                    "SYS_FBA"));
    
            for (int i = 0; i < clauses.size(); i++) {
                clauses.set(i, tableNameColumn + " NOT LIKE '" + clauses.get(i) + "%'");
            }
            return "(" + StringUtils.join(clauses, " AND ") + ")";
        }
    
        @Override
        public boolean jdbcCallsCatalogsSchemas() {
            return true;
        }
    
        public Set<String> getUserDefinedTypes() {
            if (userDefinedTypes == null) {
                userDefinedTypes = new HashSet<>();
                if ((getConnection() != null) && !(getConnection() instanceof OfflineConnection)) {
                    try {
                        try {
                            //noinspection HardCodedStringLiteral
                            userDefinedTypes.addAll(ExecutorService.getInstance().getExecutor(this).queryForList(new RawSqlStatement("SELECT DISTINCT TYPE_NAME FROM ALL_TYPES"), String.class));
                        } catch (DatabaseException e) { //fall back to USER_TYPES if the user cannot see ALL_TYPES
                            //noinspection HardCodedStringLiteral
                            userDefinedTypes.addAll(ExecutorService.getInstance().getExecutor(this).queryForList(new RawSqlStatement("SELECT TYPE_NAME FROM USER_TYPES"), String.class));
                        }
                    } catch (DatabaseException e) {
                        //ignore error
                    }
                }
            }
    
            return userDefinedTypes;
        }
    
        @Override
        public String generateDatabaseFunctionValue(DatabaseFunction databaseFunction) {
            //noinspection HardCodedStringLiteral
            if ((databaseFunction != null) && "current_timestamp".equalsIgnoreCase(databaseFunction.toString())) {
                return databaseFunction.toString();
            }
            if ((databaseFunction instanceof SequenceNextValueFunction) || (databaseFunction instanceof
                    SequenceCurrentValueFunction)) {
                String quotedSeq = super.generateDatabaseFunctionValue(databaseFunction);
                // replace "myschema.my_seq".nextval with "myschema"."my_seq".nextval
                return quotedSeq.replaceFirst("\"([^\\.\"]+)\\.([^\\.\"]+)\"", "\"$1\".\"$2\"");
    
            }
    
            return super.generateDatabaseFunctionValue(databaseFunction);
        }
    
        @Override
        public ValidationErrors validate() {
            ValidationErrors errors = super.validate();
            DatabaseConnection connection = getConnection();
            if ((connection == null) || (connection instanceof OfflineConnection)) {
                //noinspection HardCodedStringLiteral
                LogService.getLog(getClass()).info(LogType.LOG, "Cannot validate offline database");
                return errors;
            }
    
            if (!canAccessDbaRecycleBin()) {
                errors.addWarning(getDbaRecycleBinWarning());
            }
    
            return errors;
    
        }
    
        public String getDbaRecycleBinWarning() {
            //noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral,
            // HardCodedStringLiteral
            //noinspection HardCodedStringLiteral,HardCodedStringLiteral,HardCodedStringLiteral
            return "Liquibase needs to access the DBA_RECYCLEBIN table so we can automatically handle the case where " +
                    "constraints are deleted and restored. Since Oracle doesn't properly restore the original table names " +
                    "referenced in the constraint, we use the information from the DBA_RECYCLEBIN to automatically correct this" +
                    " issue.\n" +
                    "\n" +
                    "The user you used to connect to the database (" + getConnection().getConnectionUserName() +
                    ") needs to have \"SELECT ON SYS.DBA_RECYCLEBIN\" permissions set before we can perform this operation. " +
                    "Please run the following SQL to set the appropriate permissions, and try running the command again.\n" +
                    "\n" +
                    "     GRANT SELECT ON SYS.DBA_RECYCLEBIN TO " + getConnection().getConnectionUserName() + ";";
        }
    
        public boolean canAccessDbaRecycleBin() {
            if (canAccessDbaRecycleBin == null) {
                DatabaseConnection connection = getConnection();
                if ((connection == null) || (connection instanceof OfflineConnection)) {
                    return false;
                }
    
                Statement statement = null;
                try {
                    statement = ((JdbcConnection) connection).createStatement();
                    @SuppressWarnings("HardCodedStringLiteral") ResultSet resultSet = statement.executeQuery("select 1 from dba_recyclebin where 0=1");
                    resultSet.close(); //don't need to do anything with the result set, just make sure statement ran.
                    this.canAccessDbaRecycleBin = true;
                } catch (Exception e) {
                    //noinspection HardCodedStringLiteral
                    if ((e instanceof SQLException) && e.getMessage().startsWith("ORA-00942")) { //ORA-00942: table or view does not exist
                        this.canAccessDbaRecycleBin = false;
                    } else {
                        //noinspection HardCodedStringLiteral
                        LogService.getLog(getClass()).warning(LogType.LOG, "Cannot check dba_recyclebin access", e);
                        this.canAccessDbaRecycleBin = false;
                    }
                } finally {
                    JdbcUtils.close(null, statement);
                }
            }
    
            return canAccessDbaRecycleBin;
        }
    
        @Override
        public boolean supportsNotNullConstraintNames() {
            return true;
        }
    
        /**
         * Tests if the given String would be a valid identifier in Oracle DBMS. In Oracle, a valid identifier has
         * the following form (case-insensitive comparison):
         * 1st character: A-Z
         * 2..n characters: A-Z0-9$_#
         * The maximum length of an identifier differs by Oracle version and object type.
         */
        public boolean isValidOracleIdentifier(String identifier, Class<? extends DatabaseObject> type) {
            if ((identifier == null) || (identifier.length() < 1))
                return false;
    
            if (!identifier.matches("^(i?)[A-Z][A-Z0-9\\$\\_\\#]*$"))
                return false;
    
            /*
             * @todo It seems we currently do not have a class for tablespace identifiers, and all other classes
             * we do know seem to be supported as 12cR2 long identifiers, so:
             */
            return (identifier.length() <= LONG_IDENTIFIERS_LEGNTH);
        }
    
        /**
         * Returns the maximum number of bytes (NOT: characters) for an identifier. For Oracle <=12c Release 20, this
         * is 30 bytes, and starting from 12cR2, up to 128 (except for tablespaces, PDB names and some other rather rare
         * object types).
         *
         * @return the maximum length of an object identifier, in bytes
         */
        public int getIdentifierMaximumLength() {
            try {
                if (getDatabaseMajorVersion() < ORACLE_12C_MAJOR_VERSION) {
                    return SHORT_IDENTIFIERS_LENGTH;
                } else if ((getDatabaseMajorVersion() == ORACLE_12C_MAJOR_VERSION) && (getDatabaseMinorVersion() <= 1)) {
                    return SHORT_IDENTIFIERS_LENGTH;
                } else {
                    return LONG_IDENTIFIERS_LEGNTH;
                }
            } catch (DatabaseException ex) {
                throw new UnexpectedLiquibaseException("Cannot determine the Oracle database version number", ex);
            }
    
        }
    
    }
    

    第二步由于达梦数据库不能自动转换true/false为1/0,这里我覆盖了com.alibaba.druid.pool.DruidPooledStatement,将其中的executeUpdate和execute方法中待执行的SQL语句做了转换。

        @Override
        public final boolean execute(String sql) throws SQLException {
            checkOpen();
    
            incrementExecuteCount();
            transactionRecord(sql);
    
            try {
                if (StringUtils.isNotEmpty(sql)){
                    sql = sql.replace("TRUE", "1");
                    sql = sql.replace("FALSE", "0");
                }
                return stmt.execute(sql);
            } catch (Throwable t) {
                errorCheck(t);
    
                throw checkException(t, sql);
            }
        }
    

    相关文章

      网友评论

          本文标题:达梦数据库兼容问题

          本文链接:https://www.haomeiwen.com/subject/mvrupktx.html