Springboot and flowable—Dameng’s localization transformation
Article directory
- Springboot and flowable—Dameng’s localization transformation
-
- 1. Download related software
- 2. Source code execution
- 3. Database migration
- 4. Replace springboot with Dameng database
- 5. Flowable workflow integrates Dameng database
-
- 5.1 Modify the AbstractEngineConfiguration file
- 5.2 Modify the source code in [liquibase](https://so.csdn.net/so/search?q=liquibase&spm=1001.2101.3001.7020)-core-4.3.5.jar
- 5.3 Modify the liquibase.datatype.core.BooleanType class
- 5.4 修改resources/META-INF.services/liquibase.database.Database
- 5.5 Error reporting
- 6. Replace and modify the sql in the project
- 7. Notes
First of all, this example contains
1. Dameng database migration
2. SpringBoot and flowable workflow (flowable version is 6.7.0) replace Dameng database
3. SQL replacement in xml
This article should be the most detailed on the entire Internet, right? Bookmark it~
The subsequent transformation and deployment of TongWeb will be written in another article of mine.
1. Download related software
Visit Dameng official website:
1.1 Download visualization tools
First register an account
Download and select the specified version of the database management tool x86, win64
Unzip the compressed package
Double-click the .iso file and install setup.exe for fool-proof installation.
Note: Click to initialize
Create database instance
Keep going to the next step and finish.
After installation, there will be these software, as follows: Generally used are database management tools and migration tools.
ps: The username and password of the administrator in the database management tool are both SYSDBA
Note that Damengdatabase namecorresponds to the createduser name, mode corresponds to the database , that is, user object, but a Users may also create multiple schemas, so it may be necessary to specify the default schema (database) in the Springboot project configuration file.
2. Source code execution
First get the initial code of the project to be modified and run it to ensure that it is feasible before modification.
2.1 Import sql
omission
2.2 Open the project and import pom dependencies
If the installation has the following problems:
This problem is usually caused by a problem with the test class under test, causing compilation failure. For example, executing the command mvn test on the console
The error is reported as follows:
**Solution:** When compiling install, skip the execution of test first. You need to add the following configuration in pom.xml so that test errors do not affect the compilation of the project.
Add the following dependencies to pom
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<testFailureIgnore>true</testFailureIgnore>
</configuration>
</plugin>
</plugins>
</build>
After adding, clean install and then recompile, click the m icon and enter mvn idea:idea
2.3 Modify configuration
2.3.1 Modify database configuration
2.3.2 Modify redis configuration
2.3.3 Running the backend
Run directly
2.3.4 Running the front end
First open the front-end console and download the dependencies
npm install
Then modify the proxy configuration in the vue.config.js configuration file (the proxy address here is the address to access the backend interface), and connect to the backend
Then save ctrl+s, be sure to remember to save the configuration to take effect.
npm run dev
3. Database migration
Migrate the local mysql database to Dameng database. (First of all, in order not to affect the previous project code when migrating here, I chose to backup the source code and Create a new backup of a mysql database, and modify the configuration connection in yml, which will be introduced in detail below)
For migration, I chose to use the Dameng database migration tool installed above.
3.1 Create a new Dameng database (user)
As mentioned above, Dameng's database corresponds to the user object, so now create a new user (database)
The username here is the database name, which can only be in uppercase letters, and the password is the user password similar to mysql.
3.1.1 User authorization
System authorization
Click OK. A failure message will appear here. Don’t worry about it. Refresh the user after closing. The new user has been successfully created.
At this point, the user and database have been created. The schema corresponds to the database. There are corresponding database tables inside.
3.2 Use database migration tools
The SYSDBA password defaults to SYSDBA
3.2.1 New construction
3.2.2 New migration
Click next
Select mysql to dm, next step.
To connect to the source mysql database, first specify the driver
Download the mysql driver locally first
mysql driver
Link: https://pan.baidu.com/s/1nRELoWeRzcklpEtK8MNtYA
Extraction code: 1111
Complete the next step
In the same way, specify the Dameng driver and database
Dameng driver link: https://pan.baidu.com/s/1CDg2nMwY0s94Lp3gQ3j2cQ
Extraction code: 1111
Next step
Uncheck Use default data type mapping relationship, and then click the Configure type mapping relationship button on the right
Click on the lower right corner to add, the original data type name is VARCHAR, the destination data type name is VARCHAR, and the destination Enter 4 for the accuracy expansion factor and confirm
Select the Dameng database (schema) that needs to be migrated to, next step
Select the specified table and click Next
Click Finish
There is an error message here, the record is too long
Solution: First execute the script to set the table to record super-long records under Dameng, delete the data and then migrate the table data again (modify the table in Dameng database management tool).
# 选择模式
set schema TRADING_CENTER_DM;
alter table SYS_OPER_LOG enable using long row;
truncate table SYS_OPER_LOG;
select * from SYS_OPER_LOG;
Go back to the migration tool. In the previous step, select the mode and select the table to migrate the failed table again.
The database migration is complete here.
4. Replace springboot with Dameng database
4.1 Install Dameng driver jar package
The jar package address was sent when migrating above.
Install the jar package into the maven repository
mvn install:install-file -Dfile=E:\Dameng\DmJdbcDriver18.jar -DgroupId=com.dm -DartifactId=DmJdbcDriver18 -Dversion=1.8 -Dpackaging=jar
4.2 POM adds Dameng’s driver dependency
Add Dameng’s driver dependency inadmin module
<!-- DM8 jdbc -->
<dependency>
<groupId>com.dm</groupId>
<artifactId>DmJdbcDriver18</artifactId>
<version>1.8</version>
</dependency>
At this time, you will encounter a compilation error when restarting the project. It can be started before adding the pom dependency. After adding the pom dependency, you will get an error when starting the compile and build. So first modify the connection driver yml configuration.
4.3 Modify the Dameng connection driver of yml
# 数据源配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
# driverClassName: com.mysql.cj.jdbc.Driver
driverClassName: dm.jdbc.driver.DmDriver
druid:
# 主库数据源
# master:
# url: jdbc:mysql://121.43.234.114:3306/trading_center?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
# username: root
# password: gds12345678
#主库数据源(本地mysql数据库)
# master:
# url: jdbc:mysql://localhost:3306/trading_center_dm?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
# username: root
# password: 123
# 主库数据源(本地达梦数据库)
master:
url: jdbc:dm://127.0.0.1:5236?TRADING_CENTER_DM&zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8
username: SYSDBA
password: SYSDBA
# 从库数据源
slave:
# 从数据源开关/默认关闭
enabled: false
url:
username:
password:
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 10
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
webStatFilter:
enabled: true
statViewServlet:
enabled: true
# 设置白名单,不填则允许所有访问
allow:
url-pattern: /druid/*
# 控制台管理用户名和密码
login-username: ruoyi
login-password: 123456
filter:
stat:
enabled: true
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: true
wall:
config:
multi-statement-allow: true
Refer to the above modifications, rememberDameng database name is user name< a i=4>.
Note that the format of the database in the url is ? The database name is different from mysql, otherwise the URL will have the following network communication exception.
Error message:
16:46:16.112 [restartedMain] ERROR c.a.d.p.DruidDataSource - [init,931] - init datasource error, url: jdbc:dm://127.0.0.1:5236/TRADING_CENTER_DM?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8
dm.jdbc.driver.DMException: 网络通信异常
at dm.jdbc.driver.DBError.throwException(DBError.java:774)
at dm.jdbc.a.a.init(DBAccess.java:185)
at dm.jdbc.a.a.<init>(DBAccess.java:157)
at dm.jdbc.driver.DmdbConnection.openConnection(DmdbConnection.java:638)
at dm.jdbc.desc.EP.connect(EP.java:159)
at dm.jdbc.desc.EPGroup$EPSelector.select(EPGroup.java:395)
at dm.jdbc.desc.EPGroup.connect(EPGroup.java:278)
at dm.jdbc.driver.DmDriver.do_connect(DmDriver.java:163)
at dm.jdbc.driver.DmDriver.connect(DmDriver.java:449)
at com.alibaba.druid.filter.FilterChainImpl.connection_connect(FilterChainImpl.java:156)
at com.alibaba.druid.filter.stat.StatFilter.connection_connect(StatFilter.java:251)
at com.alibaba.druid.filter.FilterChainImpl.connection_connect(FilterChainImpl.java:150)
Since this project uses flowable, after startup, an error message stating that the workflow cannot find the driver type will appear as follows:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'processEngine': FactoryBean threw exception on object creation; nested exception is org.flowable.common.engine.api.FlowableException: couldn't deduct database type from database product name 'DM DBMS'
So we still have to modify flowable to integrate Dameng.
5. Flowable workflow integrates Dameng database
For pom dependencies and modifications to the Dameng driver, please refer to the above introduction. The following mainly introduces the integration of flowable with Dameng. (The version of flowable is 6.7.0)
When automatically loading the data source, flowable cannot identify the DM database type and uses overwriting the source code (that is, creating the same path as the source code class under the java package path, copying all the source code into this class, and then modifying Dameng's code ). To set the database type to MySQL or Oracle, you need to modify the file:
5.1 Modify the AbstractEngineConfiguration file
Create the org.flowable.common.engine.impl.AbstractEngineConfiguration file in the project (the paths here must be consistent, the source files will be overwritten when packaging), modify the getDefaultDatabaseTypeMappings method, and identify the Dameng database as mysql (value Setting the value to other values will report a null pointer error. So it is common to mysql),After copying the source code, modify the method in the source code, as follows
public static final String DATABASE_TYPE_DM = "mysql"; //达梦 value值设置为其他值会报错空指针。所以通用mysql
public static Properties getDefaultDatabaseTypeMappings() {
Properties databaseTypeMappings = new Properties();
databaseTypeMappings.setProperty("H2", DATABASE_TYPE_H2);
databaseTypeMappings.setProperty("HSQL Database Engine", DATABASE_TYPE_HSQL);
databaseTypeMappings.setProperty("MySQL", DATABASE_TYPE_MYSQL);
databaseTypeMappings.setProperty("MariaDB", DATABASE_TYPE_MYSQL);
databaseTypeMappings.setProperty("Oracle", DATABASE_TYPE_ORACLE);
databaseTypeMappings.setProperty(PRODUCT_NAME_POSTGRES, DATABASE_TYPE_POSTGRES);
databaseTypeMappings.setProperty("Microsoft SQL Server", DATABASE_TYPE_MSSQL);
databaseTypeMappings.setProperty(DATABASE_TYPE_DB2, DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/NT", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/NT64", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2 UDP", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/LINUX", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/LINUX390", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/LINUXX8664", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/LINUXZ64", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/LINUXPPC64", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/LINUXPPC64LE", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/400 SQL", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/6000", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2 UDB iSeries", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/AIX64", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/HPUX", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/HP64", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/SUN", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/SUN64", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/PTX", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2/2", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty("DB2 UDB AS400", DATABASE_TYPE_DB2);
databaseTypeMappings.setProperty(PRODUCT_NAME_CRDB, DATABASE_TYPE_COCKROACHDB);
databaseTypeMappings.setProperty("DM DBMS", DATABASE_TYPE_DM);// 加入达梦支持
return databaseTypeMappings;
}
5.2 modificationliquibase-core-4.3.5.jar Nakagento
Create the DmDatabase class in the java folder,The full path is liquibase.database.core.DmDatabase, refer to liquibase.database.core .OracleDatabase class, paste the following code directly into the newly created class.
The changes introduced by the author in this class are as follows:
Delete the setConnection method;
Modify the PRODUCT_NAME constant value to "DM DBMS";
Modify the getDefaultPort method to return 5236;
Modify the getShortName method to return dm;
Modify the getDefaultDriver method to return Dameng’s Driver;
The following code can be copied directly from mine. Note that the above code needs to be modified by yourself.
package liquibase.database.core;
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.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
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.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.StringUtil;
public class DmDatabase extends AbstractJdbcDatabase {
private static final String PRODUCT_NAME = "DM DBMS";
@Override
protected String getDefaultDatabaseProductName() {
return PRODUCT_NAME;
}
/**
* Is this AbstractDatabase subclass the correct one to use for the given connection.
*
* @param conn
*/
@Override
public boolean isCorrectDatabaseImplementation(DatabaseConnection conn) throws DatabaseException {
return PRODUCT_NAME.equalsIgnoreCase(conn.getDatabaseProductName());
}
/**
* If this database understands the given url, return the default driver class name. Otherwise return null.
*
* @param url
*/
@Override
public String getDefaultDriver(String url) {
if (url.startsWith("jdbc:dm")) {
return "dm.jdbc.driver.DmDriver";
}
return null;
}
/**
* Returns an all-lower-case short name of the product. Used for end-user selecting of database type
* such as the DBMS precondition.
*/
@Override
public String getShortName() {
return "dm";
}
@Override
public Integer getDefaultPort() {
return 5236;
}
/**
* Returns whether this database support initially deferrable columns.
*/
@Override
public boolean supportsInitiallyDeferrableColumns() {
return true;
}
@Override
public boolean supportsTablespaces() {
return true;
}
@Override
public int getPriority() {
return PRIORITY_DEFAULT;
}
private static final Pattern PROXY_USER = Pattern.compile(".*(?:thin|oci)\\:(.+)/@.*");
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";
}
private void tryProxySession(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("Could not open proxy session on OracleDatabase: " + e.getCause().getMessage());
}
}
}
@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 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 (StringUtil.isEmpty(generationType)) {
return super.getAutoIncrementClause();
}
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 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 Scope.getCurrentScope().getSingleton(ExecutorService.class).getExecutor("jdbc", this).queryForObject(new RawCallStatement("select sys_context( 'userenv', 'current_schema' ) from dual"), String.class);
} catch (Exception e) {
//noinspection HardCodedStringLiteral
Scope.getCurrentScope().getLog(getClass()).info("Error getting default schema", e);
}
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)) {
return "TO_DATE(" + normalLiteral + ", 'YYYY-MM-DD')";
} else if (isTimeOnly(isoDate)) {
return "TO_DATE(" + normalLiteral + ", 'HH24:MI:SS')";
} else if (isTimestamp(isoDate)) {
return "TO_TIMESTAMP(" + normalLiteral + ", 'YYYY-MM-DD HH24:MI:SS.FF')";
} else if (isDateTime(isoDate)) {
int seppos = normalLiteral.lastIndexOf('.');
if (seppos != -1) {
normalLiteral = normalLiteral.substring(0, seppos) + "'";
}
return "TO_DATE(" + normalLiteral + ", 'YYYY-MM-DD HH24:MI:SS')";
}
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 = StringUtil.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 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 "(" + StringUtil.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(Scope.getCurrentScope().getSingleton(ExecutorService.class).getExecutor("jdbc", 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(Scope.getCurrentScope().getSingleton(ExecutorService.class).getExecutor("jdbc", 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
Scope.getCurrentScope().getLog(getClass()).info("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
Scope.getCurrentScope().getLog(getClass()).warning("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);
}
}
}
5.3 Modify the liquibase.datatype.core.BooleanType class
In the same way, copy the source code to overwrite the modifications.
Add DmDatabase support in toDatabaseDataType method
Add DmDatabase type in isNumericBoolean method
The specific code is as follows: you can copy it directly
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package liquibase.datatype.core;
import java.util.Locale;
import liquibase.change.core.LoadDataChange;
import liquibase.change.core.LoadDataChange.LOAD_DATA_TYPE;
import liquibase.database.Database;
import liquibase.database.core.*;
import liquibase.datatype.DataTypeInfo;
import liquibase.datatype.DatabaseDataType;
import liquibase.datatype.LiquibaseDataType;
import liquibase.exception.UnexpectedLiquibaseException;
import liquibase.statement.DatabaseFunction;
import liquibase.util.StringUtil;
@DataTypeInfo(
name = "boolean",
aliases = {"java.sql.Types.BOOLEAN", "java.lang.Boolean", "bit", "bool"},
minParameters = 0,
maxParameters = 0,
priority = 1
)
public class BooleanType extends LiquibaseDataType {
public BooleanType() {
}
@Override
public DatabaseDataType toDatabaseDataType(Database database) {
String originalDefinition = StringUtil.trimToEmpty(getRawDefinition());
if ((database instanceof Firebird3Database)) {
return new DatabaseDataType("BOOLEAN");
}
if ((database instanceof AbstractDb2Database) || (database instanceof FirebirdDatabase)) {
return new DatabaseDataType("SMALLINT");
} else if (database instanceof MSSQLDatabase) {
return new DatabaseDataType(database.escapeDataTypeName("bit"));
} else if (database instanceof MySQLDatabase) {
if (originalDefinition.toLowerCase(Locale.US).startsWith("bit")) {
return new DatabaseDataType("BIT", getParameters());
}
return new DatabaseDataType("BIT", 1);
} else if (database instanceof OracleDatabase) {
return new DatabaseDataType("NUMBER", 1);
} else if ((database instanceof SybaseASADatabase) || (database instanceof SybaseDatabase)) {
return new DatabaseDataType("BIT");
} else if (database instanceof DerbyDatabase) {
if (((DerbyDatabase) database).supportsBooleanDataType()) {
return new DatabaseDataType("BOOLEAN");
} else {
return new DatabaseDataType("SMALLINT");
}
} else if (database.getClass().isAssignableFrom(DB2Database.class)) {
if (((DB2Database) database).supportsBooleanDataType())
return new DatabaseDataType("BOOLEAN");
else
return new DatabaseDataType("SMALLINT");
} else if (database instanceof HsqlDatabase) {
return new DatabaseDataType("BOOLEAN");
} else if (database instanceof PostgresDatabase) {
if (originalDefinition.toLowerCase(Locale.US).startsWith("bit")) {
return new DatabaseDataType("BIT", getParameters());
}
} else if(database instanceof DmDatabase) {
return new DatabaseDataType("bit");
}
return super.toDatabaseDataType(database);
}
@Override
public String objectToSql(Object value, Database database) {
if ((value == null) || "null".equals(value.toString().toLowerCase(Locale.US))) {
return null;
}
String returnValue;
if (value instanceof String) {
value = ((String) value).replaceAll("'", "");
if ("true".equals(((String) value).toLowerCase(Locale.US)) || "1".equals(value) || "b'1'".equals(((String) value).toLowerCase(Locale.US)) || "t".equals(((String) value).toLowerCase(Locale.US)) || ((String) value).toLowerCase(Locale.US).equals(this.getTrueBooleanValue(database).toLowerCase(Locale.US))) {
returnValue = this.getTrueBooleanValue(database);
} else if ("false".equals(((String) value).toLowerCase(Locale.US)) || "0".equals(value) || "b'0'".equals(
((String) value).toLowerCase(Locale.US)) || "f".equals(((String) value).toLowerCase(Locale.US)) || ((String) value).toLowerCase(Locale.US).equals(this.getFalseBooleanValue(database).toLowerCase(Locale.US))) {
returnValue = this.getFalseBooleanValue(database);
} else {
throw new UnexpectedLiquibaseException("Unknown boolean value: " + value);
}
} else if (value instanceof Long) {
if (Long.valueOf(1).equals(value)) {
returnValue = this.getTrueBooleanValue(database);
} else {
returnValue = this.getFalseBooleanValue(database);
}
} else if (value instanceof Number) {
if (value.equals(1) || "1".equals(value.toString()) || "1.0".equals(value.toString())) {
returnValue = this.getTrueBooleanValue(database);
} else {
returnValue = this.getFalseBooleanValue(database);
}
} else if (value instanceof DatabaseFunction) {
return value.toString();
} else if (value instanceof Boolean) {
if (((Boolean) value)) {
returnValue = this.getTrueBooleanValue(database);
} else {
returnValue = this.getFalseBooleanValue(database);
}
} else {
throw new UnexpectedLiquibaseException("Cannot convert type " + value.getClass() + " to a boolean value");
}
return returnValue;
}
protected boolean isNumericBoolean(Database database) {
if (database instanceof DerbyDatabase) {
return !((DerbyDatabase) database).supportsBooleanDataType();
} else if (database.getClass().isAssignableFrom(DB2Database.class)) {
return !((DB2Database) database).supportsBooleanDataType();
}
return (database instanceof Db2zDatabase) || (database instanceof DB2Database) || (database instanceof FirebirdDatabase) || (database instanceof
MSSQLDatabase) || (database instanceof MySQLDatabase) || (database instanceof OracleDatabase) ||
(database instanceof SQLiteDatabase) || (database instanceof SybaseASADatabase) || (database instanceof
SybaseDatabase) || (database instanceof DmDatabase);
}
/**
* The database-specific value to use for "false" "boolean" columns.
*/
public String getFalseBooleanValue(Database database) {
if (isNumericBoolean(database)) {
return "0";
}
if (database instanceof InformixDatabase) {
return "'f'";
}
return "FALSE";
}
/**
* The database-specific value to use for "true" "boolean" columns.
*/
public String getTrueBooleanValue(Database database) {
if (isNumericBoolean(database)) {
return "1";
}
if (database instanceof InformixDatabase) {
return "'t'";
}
return "TRUE";
}
@Override
public LoadDataChange.LOAD_DATA_TYPE getLoadTypeName() {
return LoadDataChange.LOAD_DATA_TYPE.BOOLEAN;
}
}
5.4 修改resources/META-INF.services/liquibase.database.Database
Add DmDatabase support. The modified file is as follows. Note that if you cannot find the source code, just use ctrl+shift+f to search globally. ( Also create the same file in this directory, don’t forget it, otherwise the project will not run!!!)
liquibase.database.core.CockroachDatabase
liquibase.database.core.DB2Database
liquibase.database.core.Db2zDatabase
liquibase.database.core.DerbyDatabase
liquibase.database.core.Firebird3Database
liquibase.database.core.FirebirdDatabase
liquibase.database.core.H2Database
liquibase.database.core.HsqlDatabase
liquibase.database.core.InformixDatabase
liquibase.database.core.Ingres9Database
liquibase.database.core.MSSQLDatabase
liquibase.database.core.MariaDBDatabase
liquibase.database.core.MockDatabase
liquibase.database.core.MySQLDatabase
liquibase.database.core.OracleDatabase
liquibase.database.core.PostgresDatabase
liquibase.database.core.SQLiteDatabase
liquibase.database.core.SybaseASADatabase
liquibase.database.core.SybaseDatabase
liquibase.database.core.DmDatabase
liquibase.database.core.UnsupportedDatabase
5.5 Error reporting
00:04:55.338 [restartedMain] ERROR o.f.c.e.i.d.CommonDbSchemaManager - [getProperty,198] - Could not get property from table ACT_GE_PROPERTY
dm.jdbc.driver.DMException: line 1 An error occurred near:
Invalid table or view name [ACT_GE_PROPERTY]
Error reporting solutions found online
Configure mysqlAdd: nullCatalogMeansCurrent=true when connecting. The final configuration is as follows
# 数据源配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
# driverClassName: com.mysql.cj.jdbc.Driver
driverClassName: dm.jdbc.driver.DmDriver
druid:
# 主库数据源
# master:
# url: jdbc:mysql://121.43.234.114:3306/trading_center?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
# username: root
# password: gds12345678
#主库数据源(本地mysql数据库)
# master:
# url: jdbc:mysql://localhost:3306/trading_center_dm?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
# username: root
# password: 123
# 主库数据源(本地达梦数据库)
master:
url: jdbc:dm://127.0.0.1:5236?TRADING_CENTER_DM&zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8&nullCatalogMeansCurrent=true
username: TRADING_CENTER_DM
password: TRADING_CENTER_DM
# 从库数据源
slave:
# 从数据源开关/默认关闭
enabled: false
url:
username:
password:
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 10
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
webStatFilter:
enabled: true
statViewServlet:
enabled: true
# 设置白名单,不填则允许所有访问
allow:
url-pattern: /druid/*
# 控制台管理用户名和密码
login-username: ruoyi
login-password: 123456
filter:
stat:
enabled: true
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: true
wall:
config:
multi-statement-allow: true
6. Replace and modify the sql in the project
Some function methods in mysql are not supported by Dameng, so some SQL should be replaced with methods supported by Dameng. (For more function differences, please see the official website documentation or the notes below this article)
The main modified xml sql in this project is as follows
Modified sql xml:
- SysNoticeMapper.xml (case function modification)
- GenTableColumnMapper.xml (modify the primary key of the insert statement of the gen_table_column table to increase automatically)
- SysDeptMapper.xml (modify the primary key of the insert statement of the sys_dept table to increase automatically)
- SysJobMapper.xml (modify the primary key of the insert statement of the sys_job table to increase automatically)
- SysJobLogMapper.xml (modify the primary key of the insert statement of the sys_job_log table to increase automatically)
- SysMenuMapper.xml (modify the primary key of the insert statement of the sys_menu table to increase automatically)
- SysPostMapper.xml (modify the primary key of the insert statement of the sys_post table to increase automatically)
- SysUserMapper.xml (modify the primary key of the insert statement of the sys_user table to increase automatically)
- SysJobLogMapper.xml (modify and replace date_format function)
- SysOperLogMapper.xml (modify and replace date_format function)
- GenTableColumnMapper.xml (the sql generated by the code is modified to Dameng's writing method)
6.1 Replace the find_in_set function
Since Dameng database does not have a built-in find_in_set function, but it is used in the project, it is necessary to customize the function to facilitate subsequent program calls.
Switch mode first
set schema TRADING_CENTER_DM;
Create the function FIND_IN_SET again
CREATE OR REPLACE FUNCTION FIND_IN_SET
(
piv_str1 varchar2,
piv_str2 varchar2,
p_sep varchar2 := ',')
RETURN NUMBER
IS
l_idx number:=0; -- 用于计算piv_str2中分隔符的位置
str varchar2(500); -- 根据分隔符截取的子字符串
piv_str varchar2(500) := piv_str2; -- 将piv_str2赋值给piv_str
res number :=0; -- 返回结果
loopIndex number :=0;
BEGIN
-- 如果piv_str中没有分割符,直接判断piv_str1和piv_str是否相等,相等 res=1
IF instr(piv_str, p_sep, 1) = 0 THEN
IF piv_str = piv_str1 THEN
res := 1;
END IF;
ELSE
-- 循环按分隔符截取piv_str
LOOP
l_idx := instr(piv_str, p_sep);
loopIndex:=loopIndex+1;
-- 当piv_str中还有分隔符时
IF l_idx > 0 THEN
-- 截取第一个分隔符前的字段str
str:= substr(piv_str, 1, l_idx-1);
-- 判断 str 和piv_str1 是否相等,相等 res=1 并结束循环判断
IF str = piv_str1 THEN
res:= loopIndex;
EXIT;
END IF;
piv_str := substr(piv_str, l_idx+length(p_sep));
ELSE
-- 当截取后的piv_str 中不存在分割符时,判断piv_str和piv_str1是否相等,相等 res=1
IF piv_str = piv_str1 THEN
res:= loopIndex;
END IF;
-- 无论最后是否相等,都跳出循环
EXIT;
END IF;
END LOOP;
-- 结束循环
END IF;
-- 返回res
RETURN res;
END FIND_IN_SET;
commit;
6.2 Replace case() function
cast(), mysq has it, Dameng does not.
cast(xxx as SIGNED INTEGER) -- mysql函数
替换为
to_number(xxx) -- 达梦函数
cast(notice_content as char) --mysql函数 notice_content是longblob类型 转为了char
替换为
CONVERT(notice_content, SQL_CHAR) --达梦函数 notice_content是blob类型 转为了char
6.3 Modify SQL according to Dameng’s primary key auto-increment
Dameng's primary key auto-increment does not allow that field name to appear in the INSERT INTO statement. Even if the value is null, an error will be reported.
mistake
INSERT INTO sys_logs_method ( Id, ActionTime, ActionBy, Type, IsDelete, Remark, Ip, ActionByName, ProjectNo, actionByAccount ) VALUES ( 0, ?, ?, ?, ?, ?, ?, ?, ?, ? )
mistake
INSERT INTO sys_logs_method ( Id, ActionTime, ActionBy, Type, IsDelete, Remark, Ip, ActionByName, ProjectNo, actionByAccount ) VALUES ( null, ?, ?, ?, ?, ?, ?, ?, ?, ? )
correct
INSERT INTO sys_logs_method ( ActionTime, ActionBy, Type, IsDelete, Remark, Ip, ActionByName, ProjectNo, actionByAccount ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? )
For details of the modified xml statements, see Table of Contents 6.
6.4 Modify and replace date_format function
Dameng does not support the date_sub function, use dateadd(datepart,n,date) instead, where datepart can be: year(yy,yyyy), quarter(qq,q), month(mm,m), dayofyear(dy,y) ), day(dd,d), week(wk,ww), weekday(dw), hour(hh), minute(mi,n), second(ss,s), millisecond(ms),
select dateadd(month, -6, now()); --dameng
select dateadd(month, 2, now()); --dameng
Replacement example:
date_format(create_time,'%y%m%d') --mysql
替换为达梦
to_char(create_time, 'YYMMDD') --dameng
6.5 case-when-then-else is not supported
case-when-then-else is not supported
Here is an example of case-when generated by code in the Zoey framework
mysql writing method
<select id="selectDbTableColumnsByName" parameterType="String" resultMap="GenTableColumnResult">
select column_name, (case when (is_nullable = 'no' <![CDATA[ && ]]> column_key != 'PRI') then '1' else null end) as is_required, (case when column_key = 'PRI' then '1' else '0' end) as is_pk, ordinal_position as sort, column_comment, (case when extra = 'auto_increment' then '1' else '0' end) as is_increment, column_type
from information_schema.columns where table_schema = (select database()) and table_name = (#{tableName})
order by ordinal_position
</select>
Change your dream
<select id="selectDbTableColumnsByName" parameterType="String" resultMap="GenTableColumnResult">
select t3.COLUMN_NAME as column_name,
(CASE
WHEN (t3.NULLABLE = 'N' and t4.CONSTRAINT_TYPE !='P') THEN '1'
ELSE NULL END)
as is_required,
IF(t4.CONSTRAINT_TYPE = 'P', 1, 0) as is_pk,
t3.COLUMN_ID as sort,
t5.COMMENTS as column_comment,
( CASE
WHEN (t3.TYPE = 'INT' OR t3.TYPE = 'INTEGER' OR t3.TYPE = 'BIGINT' OR t3.TYPE = 'TINYINT' OR
t3.TYPE = 'SMALLINT') and t4.CONSTRAINT_TYPE = 'P' THEN '1'
ELSE '0' END ) AS is_increment,
DATA_TYPE as DATA_TYPE
from ((select COLUMN_NAME,
COLUMN_ID,
concat(DATA_TYPE, '(', DATA_LENGTH, ')') as DATA_TYPE,
DATA_TYPE as TYPE,
TABLE_NAME,
NULLABLE
from SYS.USER_TAB_COLUMNS
WHERE table_name = (#{tableName})) t3
left join (select COMMENTS, COLUMN_NAME, TABLE_NAME from SYS.USER_COL_COMMENTS) t5
ON (t3.COLUMN_NAME = t5.COLUMN_NAME and t3.TABLE_NAME = t5.TABLE_NAME)
left join
(select t1.CONSTRAINT_TYPE, t1.OWNER, t1.TABLE_NAME, t2.CONSTRAINT_NAME, t2.COLUMN_NAME
from (select CONSTRAINT_NAME, CONSTRAINT_TYPE, OWNER, TABLE_NAME from SYS.USER_CONSTRAINTS) t1
inner join (select CONSTRAINT_NAME, OWNER, TABLE_NAME, COLUMN_NAME from SYS.USER_CONS_COLUMNS) t2
ON (t1.TABLE_NAME = t2.TABLE_NAME and t1.CONSTRAINT_NAME = t2.CONSTRAINT_NAME)
where t1.CONSTRAINT_TYPE = 'P') t4 ON (t3.COLUMN_NAME = t4.COLUMN_NAME and t3.TABLE_NAME = t4.TABLE_NAME))
order by t3.COLUMN_ID
</select>
If the code generation of the framework is used, there are several XML methods that also need to be replaced, as follows:
<select id="selectDbTableList" parameterType="GenTable" resultMap="GenTableResult">
select t1.TABLE_NAME as table_name, t2.COMMENTS as table_comment, NULL as create_time, NULL as update_time
from SYS.USER_TABLES t1
inner join SYS.USER_TAB_COMMENTS t2 ON t1.TABLE_NAME = t2.TABLE_NAME
WHERE t1.TABLE_NAME NOT LIKE 'qrtz_%'
AND t1.TABLE_NAME NOT LIKE 'gen_%'
AND t1.TABLE_NAME NOT IN (select table_name as TABLE_NAME from gen_table)
<if test="tableName != null and tableName != ''">
AND lower(t1.TABLE_NAME) like lower(concat('%', #{tableName}, '%'))
</if>
<if test="tableComment != null and tableComment != ''">
AND lower(t1.TABLE_NAME) like lower(concat('%', #{tableName}, '%'))
</if>
</select>
<select id="selectDbTableListByNames" resultMap="GenTableResult">
select t1.TABLE_NAME as table_name, t2.COMMENTS as table_comment, NULL as create_time, NULL as update_time
from SYS.USER_TABLES t1
inner join SYS.USER_TAB_COMMENTS t2 ON t1.TABLE_NAME = t2.TABLE_NAME
WHERE t1.TABLE_NAME NOT LIKE 'qrtz_%'
AND t1.TABLE_NAME NOT LIKE 'gen_%'
and t1.TABLE_NAME in
<foreach collection="array" item="name" open="(" separator="," close=")">
#{name}
</foreach>
</select>
<select id="selectTableByName" parameterType="String" resultMap="GenTableResult">
select t1.TABLE_NAME as table_name, t2.COMMENTS as table_comment, NULL as create_time, NULL as update_time
from SYS.USER_TABLES t1
inner join SYS.USER_TAB_COMMENTS t2 ON t1.TABLE_NAME = t2.TABLE_NAME
where t2.COMMENTS <![CDATA[ <> ]]> ''
and t1.TABLE_NAME = #{tableName}
</select>
7. Notes
7.1 How to modify source code
According to the source file path, create a new java class file under the java package, paste the code in the source file into the newly created file, modify the relevant code, save and compile.
Find the compiled class file in the target
Find the jar package where the source file is located, right-click and open it in file management.
Unzip the jar package, paste the modified and compiled class file in the target into the corresponding location of the jar package, then repackage it into a zip package and change the suffix to .jar
Comment: Can the source code in the jar package be submitted using git after modification?
When you modify the source code in a JAR package, you actually modify a copy of the JAR package. This modification will not affect the original JAR package, so these modifications cannot be submitted directly using Git.
7.2 When starting the Maven project, the package does not exist and an error message is reported.
If there is no problem with any dependencies, this is usually a project compilation problem. Recompile the project.
Click the M button in Maven, then enter the following command to recompile the project and run it.
mvn idea:idea
7.3 Differences in some sql functions between mysql and Dameng
Only common differences are provided here. Details must be tested according to the modified functions, or refer to official documents.
(1) When creating a table, adding comment comments directly after the column is not supported. Use COMMENT ON IS instead, such as:
COMMENT ON TABLE xxx IS xxx
COMMENT ON COLUMN xxx IS xxx
(2) The date_sub function is not supported, use dateadd(datepart,n,date) instead, where datepart can be: year(yy,yyyy), quarter(qq,q), month(mm,m), dayofyear(dy, y), day(dd,d), week(wk,ww), weekday(dw), hour(hh), minute(mi,n), second(ss,s), millisecond(ms), example:
select dateadd(month, -6, now());
select dateadd(month, 2, now());
(3) The date_format function is not supported. It has three substitution methods:
A: Use datepart instead: Syntax: datepart(datepart, date), returns the specified part representing the date Integer, datepart can be: year(yy,yyyy), quarter(qq,q), month(mm,m), dayofyear(dy,y), day(dd,d), week(wk,ww), weekday( dw), hour(hh), minute(mi,n), second(ss,s), millisecond(ms), example:
select datepart(year, '2023-04-13 08:45:00'); --2023
select datepart(month, '2022-12-13 08:45:00'); --12
B: Use date_part instead. The function is the same as datepart, but the writing method is different. The order of parameters is reversed, and they must be enclosed in quotation marks. Example:
select date_part('2023-12-13 08:45:00', 'year');--2023
select date_part('2022-12-13 08:45:00', 'mm'); -- 12
C: Use extract instead, syntax: extract(dtfield from date), extract the value corresponding to dtfield from the date type date, dtfield can be year, month, day, hour, minute, second, example:
select extract(year from '2023-12-13 08:45:00'); --2023
select extract(month from '2022-12-13 08:45:00'); --12
(4) The substring_index function is not supported, use substr / substring instead, syntax:
substr(char[,m[,n]])
substring(char[from m[ for n]])
(5) The group_concat function is not supported, use wm_concat instead, example:
select wm_concat(id) as idstr from persion ORDER BY id ;
(6) The from_unixtime function is not supported, use round instead, syntax:
round(date[,format])
(7) case-when-then-else is not supported, for example:
select case when id = 2 then "aaa" when id = 3 then "bbb" else "ccc" end as test from (select id from person) tt;
(8) The return value of current_timestamp has time zone, example:
select current_timestamp();
2023-04-37 14:34:18.433839 +08:00
r(yy,yyyy),quarter(qq,q),month(mm,m),dayofyear(dy,y),day(dd,d),week(wk,ww),weekday(dw),hour(hh), minute(mi,n), second(ss,s), millisecond(ms),例子:
select dateadd(month, -6, now());
select dateadd(month, 2, now());
(3) The date_format function is not supported. It has three substitution methods:
A: Use datepart instead: Syntax: datepart(datepart, date), returns the specified part representing the date Integer, datepart can be: year(yy,yyyy), quarter(qq,q), month(mm,m), dayofyear(dy,y), day(dd,d), week(wk,ww), weekday( dw), hour(hh), minute(mi,n), second(ss,s), millisecond(ms), example:
select datepart(year, '2023-04-13 08:45:00'); --2023
select datepart(month, '2022-12-13 08:45:00'); --12
B: Use date_part instead. The function is the same as datepart, but the writing method is different. The order of parameters is reversed, and they must be enclosed in quotation marks. Example:
select date_part('2023-12-13 08:45:00', 'year');--2023
select date_part('2022-12-13 08:45:00', 'mm'); -- 12
C: Use extract instead, syntax: extract(dtfield from date), extract the value corresponding to dtfield from the date type date, dtfield can be year, month, day, hour, minute, second, example:
select extract(year from '2023-12-13 08:45:00'); --2023
select extract(month from '2022-12-13 08:45:00'); --12
(4) The substring_index function is not supported, use substr / substring instead, syntax:
substr(char[,m[,n]])
substring(char[from m[ for n]])
(5) The group_concat function is not supported, use wm_concat instead, example:
select wm_concat(id) as idstr from persion ORDER BY id ;
(6) The from_unixtime function is not supported, use round instead, syntax:
round(date[,format])
(7) case-when-then-else is not supported, for example:
select case when id = 2 then "aaa" when id = 3 then "bbb" else "ccc" end as test from (select id from person) tt;
(8) The return value of current_timestamp has time zone, example:
select current_timestamp();
2023-04-37 14:34:18.433839 +08:00