信创背景下MySQL到达梦数据库的SQL语法转换技术解析
一、背景介绍
在信创(信息技术应用创新)产业快速发展的背景下,国产数据库的替代已成为必然趋势。达梦数据库作为国产数据库的重要代表,在企业级应用中逐渐取代MySQL等国外数据库产品。然而,由于SQL语法在不同数据库间存在差异,如何实现平滑迁移成为亟需解决的技术难题。
本文基于实际的SQL语法转换器实现,深入解析MySQL到达梦数据库的SQL转换技术方案。
二、整体架构设计
2.1 核心转换流程
SQL转换器的核心架构采用抽象语法树(AST)解析+策略模式的设计:
// 基类定义通用转换框架
public abstract class BaseConverter {
// 存储各类SQL语句的转换结果
public List<String> creatTableList = new ArrayList<>();
public List<String> commentList = new ArrayList<>();
// ...其他语句列表
// 策略映射表:语句类型→处理函数
private final Map<Class<?>, Consumer<Object>> conversionStrategies = new HashMap<>();
// 初始化策略映射
public BaseConverter() {
conversionStrategies.put(MySqlCreateTableStatement.class, stmt -> convertCreateTabletStatement((MySqlCreateTableStatement) stmt));
conversionStrategies.put(MySqlInsertStatement.class, stmt -> convertInsertStatement((MySqlInsertStatement) stmt));
// ...其他语句类型映射
}
}
2.2 转换执行流程
- SQL解析:使用Druid解析器将原始SQL转换为AST
- 语句分发:根据语句类型选择对应的处理策略
- 语法转换:针对特定数据库进行语法适配
- 结果收集:将转换后的SQL语句分类存储
三、关键技术实现
3.1 函数映射转换
不同数据库的函数差异是转换的重点难点,我们采用函数映射表的方式解决:
// MySQL与达梦函数映射表
private static final Map<String, String> FUNCTION_MAPPING = new HashMap<>();
static {
FUNCTION_MAPPING.put("CONCAT", "||");
FUNCTION_MAPPING.put("NOW()", "SYSDATE");
FUNCTION_MAPPING.put("DATE_FORMAT", "TO_CHAR");
FUNCTION_MAPPING.put("SUBSTRING", "SUBSTR");
FUNCTION_MAPPING.put("IFNULL", "NVL");
FUNCTION_MAPPING.put("UUID", "SYS_GUID");
// ...更多函数映射
}
3.2 分页语法转换
MySQL的LIMIT语法与达梦的ROWNUM语法存在显著差异:
private static String convertPagination(String query) {
// 转换 LIMIT offset, size 语法
Pattern pattern1 = Pattern.compile("LIMIT\\s+(\\d+)\\s*,\\s*(\\d+)", Pattern.CASE_INSENSITIVE);
Matcher matcher1 = pattern1.matcher(query);
if (matcher1.find()) {
String offset = matcher1.group(1);
String limit = matcher1.group(2);
return matcher1.replaceFirst("OFFSET " + offset + " FETCH FIRST " + limit + " ROWS ONLY");
}
// 其他分页模式处理...
}
3.3 数据类型映射
数据类型在不同数据库间存在差异,需要特殊处理:
// 数据类型转换示例
if ("VARCHAR".equals(dataTypeName)) {
builder.append("\"").append(columnName).append("\" ").append(dataTypeName)
.append("(").append(sqlIntegerExpr.getNumber()).append(")");
} else if ("TIMESTAMP".equals(dataTypeName) || "DATETIME".equals(dataTypeName)) {
builder.append("\"").append(columnName).append("\" ").append("TIMESTAMP(0)");
} else if ("BIT".equals(dataTypeName)) {
builder.append("\"").append(columnName).append("\" ").append("TINYINT");
}
// ...更多类型处理
四、复杂语句处理
4.1 CREATE TABLE语句解析
建表语句涉及表结构、约束、索引等多方面内容:
@Override
public void convertCreateTabletStatement(MySqlCreateTableStatement statement) {
String tableName = statement.getTableName().replace("`", "").toUpperCase();
// 处理表注释
if (Objects.nonNull(statement.getComment())) {
commentList.add("COMMENT ON TABLE \"" + tableName + "\"" + " IS '" + comment + "';");
}
// 处理表元素(列、约束等)
statement.getTableElementList().forEach(column -> {
if (column instanceof SQLColumnDefinition) {
// 列定义处理
processColumnDefinition((SQLColumnDefinition) column, tableName);
} else if (column instanceof MySqlPrimaryKey) {
// 主键约束处理
processPrimaryKey((MySqlPrimaryKey) column, tableName);
}
// ...其他元素类型
});
}
4.2 SELECT查询处理
查询语句需要处理函数、别名、关联查询等复杂场景:
private String processSelectQuery(SQLSelectQuery query) {
if (query instanceof SQLSelectQueryBlock) {
SQLSelectQueryBlock block = (SQLSelectQueryBlock) query;
// 处理SELECT子句
processSelectItems(block.getSelectList());
// 处理FROM子句
processTableSource(block.getFrom());
// 处理WHERE条件
processWhereCondition(block.getWhere());
// 处理GROUP BY和HAVING
processGroupBy(block.getGroupBy());
// 处理分页
processLimit(block.getLimit());
}
// ...联合查询处理
}
五、特殊场景处理
5.1 自增字段处理
达梦使用IDENTITY语法替代MySQL的AUTO_INCREMENT:
if (autoIncrement) {
if (StringUtils.isNotBlank(increment)) {
builder.append(" IDENTITY(").append(increment).append(",1)");
} else {
builder.append(" IDENTITY(1,1)");
}
}
5.2 索引和约束处理
不同数据库的索引创建语法需要适配:
// 唯一索引转换
if ("UNIQUE".equals(type)) {
String indexName = "UNIQUE_" + tableName + "_" + StringUtils.join(keys, "_");
indexList.add("ALTER TABLE \"" + tableName + "\" ADD CONSTRAINT \"" + indexName
+ "\" UNIQUE(" + StringUtils.join(keys, ",") + ");");
} else {
// 普通索引
String indexName = "IDX_" + tableName + "_" + StringUtils.join(keys, "_");
indexList.add("CREATE INDEX \"" + indexName + "\" ON \"" + tableName
+ "\"(" + StringUtils.join(keys, ",") + ");");
}
六、转换效果示例
MySQL原始SQL:
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表';
SELECT * FROM `user` WHERE DATE_FORMAT(create_time, '%Y-%m-%d') = '2023-01-01' LIMIT 10;
转换后的达梦SQL:
CREATE TABLE "USER" (
"ID" INT IDENTITY(1,1) NOT NULL,
"NAME" VARCHAR(50) NULL,
"CREATE_TIME" TIMESTAMP(0) DEFAULT CURRENT_TIMESTAMP NULL
);
COMMENT ON TABLE "USER" IS '用户表';
COMMENT ON COLUMN "USER"."ID" IS '';
SELECT * FROM "USER" WHERE TO_CHAR(CREATE_TIME, 'YYYY-MM-DD') = '2023-01-01' FETCH FIRST 10 ROWS ONLY;
七、原始代码
基础代码
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLCreateIndexStatement;
import com.alibaba.druid.sql.ast.statement.SQLDropTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import com.alibaba.druid.sql.ast.statement.SQLTruncateStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDeleteStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlInsertStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlRenameTableStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlUpdateStatement;
import com.alibaba.druid.util.JdbcConstants;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public abstract class BaseConverter {
/**
* createTable sql语句
*/
public List<String> creatTableList = new ArrayList<>();
/**
* comment sql语句
*/
public List<String> commentList = new ArrayList<>();
/**
* index sql语句
*/
public List<String> indexList = new ArrayList<>();
/**
* alter sql语句
*/
public List<String> alterList = new ArrayList<>();
/**
* insert sql语句
*/
public List<String> insertList = new ArrayList<>();
/**
* update sql语句
*/
public List<String> updateList = new ArrayList<>();
/**
* select sql语句
*/
public List<String> selectList = new ArrayList<>();
/**
* sequence sql语句
*/
public List<String> sequenceList = new ArrayList<>();
/**
* alterSequence sql语句
*/
public List<String> alterSequenceList = new ArrayList<>();
/**
* sql别名及函数
*/
public final Map<String, SQLExpr> selectAliasMap = new HashMap<>();
/**
* SQL语法树映射
*/
private final Map<Class<?>, Consumer<Object>> conversionStrategies = new HashMap<>();
/**
* 初始化策略映射
*/
public BaseConverter() {
conversionStrategies.put(MySqlCreateTableStatement.class, stmt -> convertCreateTabletStatement((MySqlCreateTableStatement) stmt));
conversionStrategies.put(MySqlInsertStatement.class, stmt -> convertInsertStatement((MySqlInsertStatement) stmt));
conversionStrategies.put(SQLCreateIndexStatement.class, stmt -> convertCreateIndexStatement((SQLCreateIndexStatement) stmt));
conversionStrategies.put(MySqlUpdateStatement.class, stmt -> convertUpdateStatement((MySqlUpdateStatement) stmt));
conversionStrategies.put(MySqlDeleteStatement.class, stmt -> convertDeleteStatement((MySqlDeleteStatement) stmt));
conversionStrategies.put(SQLAlterTableStatement.class, stmt -> convertAlterTableStatement((SQLAlterTableStatement) stmt));
conversionStrategies.put(MySqlRenameTableStatement.class, stmt -> convertRenameTableStatement((MySqlRenameTableStatement) stmt));
conversionStrategies.put(SQLDropTableStatement.class, stmt -> convertDropTableStatement((SQLDropTableStatement) stmt));
conversionStrategies.put(SQLTruncateStatement.class, stmt -> convertTruncateStatement((SQLTruncateStatement) stmt));
conversionStrategies.put(SQLSelectStatement.class, stmt -> convertQueryStatement((SQLSelectStatement) stmt));
}
/**
* 转换器适配
*
* @param dbType 数据库类型
* @return 是否适配
*/
abstract boolean support(String dbType);
/**
* 翻译转换
*
* @return 结果集
*/
public List<String> convert(String schemaName, String originalSql) {
List<SQLStatement> stmtList = SQLUtils.parseStatements(originalSql, JdbcConstants.MYSQL);
List<String> result = new ArrayList<>();
stmtList.forEach(statement -> {
// 语法树翻译转化
processConvertStatement(statement);
List<String> collect = Stream.of(creatTableList, alterSequenceList, sequenceList, commentList, indexList, alterList, insertList, updateList, selectList).
flatMap(Collection::stream).
filter(Objects::nonNull).
collect(Collectors.toList());
if (collect.isEmpty()) {
collect.add(statement.toString());
}
result.addAll(collect);
});
return result;
}
/**
* 语法树翻译转化
*
* @param statement 抽象语法树
*/
private void processConvertStatement(SQLStatement statement) {
Consumer<Object> consumer = conversionStrategies.get(statement.getClass());
if (Objects.isNull(consumer)) {
log.error("Unsupported statement type: " + statement.getClass());
return;
}
consumer.accept(statement);
}
/**
* DDL-CREATE 语法树转换
*
* @param statement 语法树
*/
abstract void convertCreateTabletStatement(MySqlCreateTableStatement statement);
/**
* DML-INSERT 语法树转换
*
* @param statement 语法树
*/
abstract void convertInsertStatement(MySqlInsertStatement statement);
/**
* DDL-INDEX 语法树转换
*
* @param statement 语法树
*/
abstract void convertCreateIndexStatement(SQLCreateIndexStatement statement);
/**
* DML-UPDATE 语法树转换
*
* @param statement 语法树
*/
abstract void convertUpdateStatement(MySqlUpdateStatement statement);
/**
* DML-DELETE 语法树转换
*
* @param statement 语法树
*/
abstract void convertDeleteStatement(MySqlDeleteStatement statement);
/**
* DLL-ALTER TABLE 语法树转换
*
* @param statement 语法树
*/
abstract void convertAlterTableStatement(SQLAlterTableStatement statement);
/**
* DDL-RENAME 语法树转换
*
* @param statement 语法树
*/
abstract void convertRenameTableStatement(MySqlRenameTableStatement statement);
/**
* DDL-Drop语法树转换
*
* @param statement 语法树
*/
abstract void convertDropTableStatement(SQLDropTableStatement statement);
/**
* 截断操作语法树转换
*
* @param statement 语法树
*/
abstract void convertTruncateStatement(SQLTruncateStatement statement);
/**
* 查询语法树转换
*
* @param statement 语法树
*/
abstract void convertQueryStatement(SQLSelectStatement statement);
}
达梦代码
import com.alibaba.druid.sql.ast.SQLCurrentTimeExpr;
import com.alibaba.druid.sql.ast.SQLDataTypeImpl;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLIndexDefinition;
import com.alibaba.druid.sql.ast.SQLLimit;
import com.alibaba.druid.sql.ast.SQLObject;
import com.alibaba.druid.sql.ast.SQLOrderBy;
import com.alibaba.druid.sql.ast.SQLOrderingSpecification;
import com.alibaba.druid.sql.ast.expr.SQLAggregateExpr;
import com.alibaba.druid.sql.ast.expr.SQLBinaryExpr;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator;
import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLInListExpr;
import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
import com.alibaba.druid.sql.ast.expr.SQLNullExpr;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddColumn;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddConstraint;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddIndex;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLAssignItem;
import com.alibaba.druid.sql.ast.statement.SQLColumnConstraint;
import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
import com.alibaba.druid.sql.ast.statement.SQLConstraint;
import com.alibaba.druid.sql.ast.statement.SQLCreateIndexStatement;
import com.alibaba.druid.sql.ast.statement.SQLDropTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLExprStatement;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource;
import com.alibaba.druid.sql.ast.statement.SQLNotNullConstraint;
import com.alibaba.druid.sql.ast.statement.SQLSelect;
import com.alibaba.druid.sql.ast.statement.SQLSelectItem;
import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem;
import com.alibaba.druid.sql.ast.statement.SQLSelectQuery;
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import com.alibaba.druid.sql.ast.statement.SQLSubqueryTableSource;
import com.alibaba.druid.sql.ast.statement.SQLTableElement;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.ast.statement.SQLTruncateStatement;
import com.alibaba.druid.sql.ast.statement.SQLUnionQuery;
import com.alibaba.druid.sql.dialect.mysql.ast.MySqlKey;
import com.alibaba.druid.sql.dialect.mysql.ast.MySqlPrimaryKey;
import com.alibaba.druid.sql.dialect.mysql.ast.MySqlUnique;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableChangeColumn;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableModifyColumn;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDeleteStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlInsertStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlRenameTableStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlUpdateStatement;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
import com.alibaba.druid.sql.visitor.SQLASTVisitorAdapter;
import com.alibaba.druid.util.JdbcConstants;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class DamengConverter extends BaseConverter {
/**
* 初始化策略映射
*/
public DamengConverter() {
super();
}
/**
* 定义MySQL和达梦数据库的函数映射
*/
private static final Map<String, String> FUNCTION_MAPPING = new HashMap<>();
static {
FUNCTION_MAPPING.put("CONCAT", "||");
FUNCTION_MAPPING.put("NOW()", "SYSDATE");
FUNCTION_MAPPING.put("CURRENT_TIMESTAMP", "CURRENT_TIMESTAMP");
FUNCTION_MAPPING.put("DATE_FORMAT", "TO_CHAR");
FUNCTION_MAPPING.put("SUBSTRING", "SUBSTR");
FUNCTION_MAPPING.put("DATEDIFF", "-");
FUNCTION_MAPPING.put("IFNULL", "NVL");
FUNCTION_MAPPING.put("UUID", "SYS_GUID");
FUNCTION_MAPPING.put("GROUP_CONCAT", "WM_CONCAT");
FUNCTION_MAPPING.put("FIND_IN_SET", "INSTR");
FUNCTION_MAPPING.put("UNIX_TIMESTAMP", "EXTRACT(EPOCH FROM SYSDATE)");
FUNCTION_MAPPING.put("LOCATE", "INSTR");
FUNCTION_MAPPING.put("COALESCE", "COALESCE");
FUNCTION_MAPPING.put("REPLACE", "REPLACE");
}
/**
* 转换器适配
*
* @param dbType 数据库类型
* @return 是否适配
*/
@Override
public boolean support(String dbType) {
return JdbcConstants.DM.name().equals(dbType);
}
private static String convertPagination(String query) {
// 匹配 LIMIT offset, size
Pattern pattern1 = Pattern.compile("LIMIT\\s+(\\d+)\\s*,\\s*(\\d+)", Pattern.CASE_INSENSITIVE);
Matcher matcher1 = pattern1.matcher(query);
if (matcher1.find()) {
String offset = matcher1.group(1);
String limit = matcher1.group(2);
return matcher1.replaceFirst("OFFSET " + offset + " FETCH FIRST " + limit + " ROWS ONLY");
}
// 匹配 LIMIT size OFFSET offset
Pattern pattern2 = Pattern.compile("LIMIT\\s+(\\d+)\\s+OFFSET\\s+(\\d+)", Pattern.CASE_INSENSITIVE);
Matcher matcher2 = pattern2.matcher(query);
if (matcher2.find()) {
String limit = matcher2.group(1);
String offset = matcher2.group(2);
return matcher2.replaceFirst("OFFSET " + offset + " FETCH FIRST " + limit + " ROWS ONLY");
}
return query;
}
@Override
public void convertQueryStatement(SQLSelectStatement statement) {
SQLSelect select = statement.getSelect();
if (select != null) {
SQLSelectQuery query = select.getQuery();
if (query != null) {
String convertedSql = processSelectQuery(query);
if (StringUtils.isNotBlank(convertedSql)) {
selectList.add(convertedSql);
}
}
}
}
private String processSelectQuery(SQLSelectQuery query) {
StringBuilder sb = new StringBuilder();
if (query instanceof SQLSelectQueryBlock) {
SQLSelectQueryBlock block = (SQLSelectQueryBlock) query;
// SELECT 列
sb.append("SELECT ");
List<SQLSelectItem> selectItems = block.getSelectList();
for (int i = 0; i < selectItems.size(); i++) {
if (i > 0) {
sb.append(", ");
}
sb.append(processSelectItem(selectItems.get(i)));
}
// FROM 子句
SQLTableSource from = block.getFrom();
if (from != null) {
sb.append(" FROM ").append(processTableSource(from));
}
// WHERE 条件
SQLExpr where = block.getWhere();
if (where != null) {
sb.append(" WHERE ").append(processWhereCondition(where));
}
collectSelectAliases(block);
// GROUP BY
List<SQLExpr> groupBy = block.getGroupBy() != null ? block.getGroupBy().getItems() : Collections.emptyList();
if (!groupBy.isEmpty()) {
sb.append(" GROUP BY ");
for (int i = 0; i < groupBy.size(); i++) {
if (i > 0) {
sb.append(", ");
}
sb.append(groupBy.get(i).toString());
}
SQLExpr having = block.getGroupBy().getHaving();
if (having != null) {
SQLExpr replacedHaving = replaceAliasWithExpr(having);
sb.append(" HAVING ").append(replacedHaving.toString());
}
}
// ORDER BY
SQLOrderBy orderBy = block.getOrderBy();
if (orderBy != null) {
List<SQLSelectOrderByItem> orderByItems = orderBy.getItems();
if (orderByItems != null && !orderByItems.isEmpty()) {
sb.append(" ORDER BY ");
for (int i = 0; i < orderByItems.size(); i++) {
SQLSelectOrderByItem item = orderByItems.get(i);
if (i > 0) {
sb.append(", ");
}
sb.append(item.getExpr().toString());
if (item.getType() == SQLOrderingSpecification.DESC) {
sb.append(" DESC");
} else {
sb.append(" ASC");
}
}
}
}
// LIMIT / OFFSET 分页
SQLLimit limit = block.getLimit();
if (limit != null) {
sb.append(" ").append(convertPagination(limit.toString()));
}
} else if (query instanceof SQLUnionQuery) {
SQLUnionQuery unionQuery = (SQLUnionQuery) query;
sb.append("(").append(processSelectQuery(unionQuery.getLeft())).append(")");
sb.append(" ").append(unionQuery.getOperator()).append(" ");
sb.append("(").append(processSelectQuery(unionQuery.getRight())).append(")");
}
return sb.toString();
}
private void collectSelectAliases(SQLSelectQueryBlock block) {
selectAliasMap.clear();
for (SQLSelectItem item : block.getSelectList()) {
if (Objects.isNull(item.getAlias())) {
continue;
}
selectAliasMap.put(item.getAlias(), item.getExpr());
}
}
private SQLExpr replaceAliasWithExpr(SQLExpr expr) {
if (expr instanceof SQLIdentifierExpr) {
String aliasName = ((SQLIdentifierExpr) expr).getName();
return selectAliasMap.getOrDefault(aliasName, expr);
} else if (expr instanceof SQLBinaryOpExpr) {
SQLBinaryOpExpr binaryExpr = (SQLBinaryOpExpr) expr;
SQLExpr left = replaceAliasWithExpr(binaryExpr.getLeft());
SQLExpr right = replaceAliasWithExpr(binaryExpr.getRight());
return new SQLBinaryOpExpr(left, binaryExpr.getOperator(), right);
}
// 可继续扩展其他类型...
return expr;
}
private String processSelectItem(SQLSelectItem item) {
item.getExpr().accept(createFunctionReplaceVisitor());
String expr = item.getExpr().toString();
if (item.getAlias() != null) {
return expr + " AS " + item.getAlias();
}
return expr;
}
private String processTableSource(SQLTableSource source) {
if (source instanceof SQLExprTableSource) {
SQLIdentifierExpr expr = (SQLIdentifierExpr) ((SQLExprTableSource) source).getExpr();
return expr.getName().replace("`", "");
} else if (source instanceof SQLJoinTableSource) {
SQLJoinTableSource join = (SQLJoinTableSource) source;
String left = processTableSource(join.getLeft());
String right = processTableSource(join.getRight());
String on = join.getCondition() != null ? " ON " + join.getCondition().toString() : "";
return left + " " + join.getJoinType().nameLCase + " " + right + on;
} else if (source instanceof SQLSubqueryTableSource) {
SQLSelect subQuery = ((SQLSubqueryTableSource) source).getSelect();
String alias = ((SQLSubqueryTableSource) source).getAlias();
return "(" + processSelectQuery(subQuery.getQuery()) + ") AS " + alias;
}
return source.toString();
}
private String processWhereCondition(SQLExpr where) {
where.accept(createFunctionReplaceVisitor());
return ((SQLSelectQueryBlock) where.getParent()).getWhere().toString();
}
private SQLASTVisitor createFunctionReplaceVisitor() {
return new SQLASTVisitorAdapter() {
@Override
public boolean visit(SQLMethodInvokeExpr expr) {
handleFunction(expr);
return true;
}
@Override
public boolean visit(SQLAggregateExpr expr) {
handleFunction(expr);
return true;
}
private void handleFunction(SQLMethodInvokeExpr expr) {
String funcName = expr.getMethodName();
System.out.println("funcName: " + funcName);
String gbaseFunc = FUNCTION_MAPPING.get(funcName.toUpperCase());
String gbaseFunc2 = gbaseFunc == null ? FUNCTION_MAPPING.get(funcName.toUpperCase() + "()") : gbaseFunc;
if (gbaseFunc2 != null) {
// 特殊处理 GROUP_CONCAT -> STRING_AGG 需要加参数
if ("GROUP_CONCAT".equalsIgnoreCase(funcName)) {
handleGroupConcat(expr, gbaseFunc2);
} else if ("FIND_IN_SET".equalsIgnoreCase(funcName)) {
// FIND_IN_SET(a, b) => STRPOS(b, a) > 0
List<SQLExpr> parameters = expr.getParameters();
if (parameters.size() >= 2) {
SQLExpr a = parameters.get(0); // 'apple'
SQLExpr b = parameters.get(1); // fruits
// 构建 STRPOS(b, a)
SQLMethodInvokeExpr strpos = new SQLMethodInvokeExpr("INSTR");
strpos.addParameter(b);
strpos.addParameter(a);
// 构建 STRPOS(...) > 0
SQLBinaryOpExpr gtZero = new SQLBinaryOpExpr(strpos, SQLBinaryOperator.GreaterThan, new SQLIntegerExpr(0));
SQLObject parent = expr.getParent();
if (parent instanceof SQLBinaryOpExpr) {
((SQLBinaryOpExpr) parent).replace(expr, gtZero);
} else if (parent instanceof SQLSelectItem) {
((SQLSelectItem) parent).setExpr(gtZero);
} else if (parent instanceof SQLExprStatement) {
((SQLExprStatement) parent).setExpr(gtZero);
} else if (parent instanceof SQLSelectQueryBlock) {
// expr.setUsing(gtZero);
//expr.replace(expr, gtZero);
((SQLSelectQueryBlock) parent).replace(expr, gtZero);
} else if (parent instanceof SQLInListExpr) {
// 处理 FIND_IN_SET 在 IN 子句中的情况
SQLInListExpr inListExpr = (SQLInListExpr) parent;
inListExpr.addTarget(gtZero);
} else {
// 其他复杂结构需要单独处理
System.err.println("Unsupported parent type: " + parent.getClass());
}
}
} else {
expr.setMethodName(gbaseFunc2.replace("()", ""));
}
}
}
private void handleGroupConcat(SQLMethodInvokeExpr expr, String gbaseFunc2) {
if (expr instanceof SQLAggregateExpr) {
SQLAggregateExpr aggExpr = (SQLAggregateExpr) expr;
List<SQLExpr> parameters = aggExpr.getArguments();
if (parameters.size() >= 1) {
SQLExpr col = parameters.get(0);
SQLCharExpr defaultSep = new SQLCharExpr(",");
SQLMethodInvokeExpr stringAgg = new SQLMethodInvokeExpr("WM_CONCAT"); // STRING_AGG
stringAgg.addParameter(col);
stringAgg.addParameter(defaultSep);
SQLObject parent = expr.getParent();
if (parent instanceof SQLBinaryOpExpr) {
((SQLBinaryOpExpr) parent).replace(expr, stringAgg);
} else if (parent instanceof SQLSelectItem) {
((SQLSelectItem) parent).setExpr(stringAgg);
}
}
} else if (expr instanceof SQLMethodInvokeExpr) {
// 处理 GROUP_CONCAT 作为普通函数的情况(如果有的话)
SQLMethodInvokeExpr methodExpr = (SQLMethodInvokeExpr) expr;
List<SQLExpr> parameters = methodExpr.getParameters();
if (parameters.size() == 1) {
SQLExpr col = parameters.get(0);
SQLCharExpr defaultSep = new SQLCharExpr(",");
SQLMethodInvokeExpr stringAgg = new SQLMethodInvokeExpr("STRING_AGG");
stringAgg.addParameter(col);
stringAgg.addParameter(defaultSep);
SQLObject parent = expr.getParent();
if (parent instanceof SQLBinaryOpExpr) {
((SQLBinaryOpExpr) parent).replace(expr, stringAgg);
} else if (parent instanceof SQLSelectItem) {
((SQLSelectItem) parent).setExpr(stringAgg);
}
}
}
}
};
}
@Override
public void convertCreateTabletStatement(MySqlCreateTableStatement statement) {
String tableName = statement.getTableName()
.replace("`", "").replace("\"", "").toUpperCase();
String comment = null;
if (Objects.nonNull(statement.getComment())) {
comment = statement.getComment().toString().replace("'", "").replace("\"", "");
}
List<SQLTableElement> tableElementList = statement.getTableElementList();
List<SQLAssignItem> tableOptions = statement.getTableOptions();
Map<String, Object> sqlAssignMap = new HashMap<>();
tableOptions.forEach(option -> {
sqlAssignMap.put(option.getTarget().toString(), option.getValue());
});
if (StringUtils.isNotBlank(comment)) {
commentList.add("COMMENT ON TABLE \"" + tableName + "\"" + " IS '" + comment + "';");
}
StringBuilder builder = new StringBuilder("CREATE TABLE ");
builder.append("\"").append(tableName).append("\"").append("\n(");
tableElementList.forEach(column -> {
if (column instanceof SQLColumnDefinition) {
SQLCharExpr commentSqlExpr = (SQLCharExpr) ((SQLColumnDefinition) column).getComment();
String columnName = ((SQLColumnDefinition) column).getColumnName().replace("`", "").replace("\"", "").toUpperCase();
String columnComment = null;
if (Objects.nonNull(commentSqlExpr)) {
columnComment = commentSqlExpr.getText();
}
String autoIncrement = null;
if (sqlAssignMap.containsKey("AUTO_INCREMENT")) {
autoIncrement = sqlAssignMap.get("AUTO_INCREMENT").toString();
}
builder.append(buildColumn((SQLColumnDefinition) column, autoIncrement));
builder.append(",\n");
if (StringUtils.isNotBlank(columnComment)) {
commentList.add("COMMENT ON COLUMN \"" + tableName + "\".\"" + columnName + "\" IS '" + columnComment + "';");
}
} else if (column instanceof MySqlPrimaryKey) {
MySqlPrimaryKey mySqlPrimaryKey = (MySqlPrimaryKey) column;
List<SQLSelectOrderByItem> sqlSelectOrderByItems = mySqlPrimaryKey.getIndexDefinition().getColumns();
SQLIdentifierExpr expr = (SQLIdentifierExpr) sqlSelectOrderByItems.get(0).getExpr();
alterList.add("ALTER TABLE \"" + tableName + "\" ADD CONSTRAINT PRIMARY KEY(\"" + expr.getName().replace("`", "").toUpperCase() + "\");");
} else if (column instanceof MySqlUnique) {
MySqlUnique mySqlKey = (MySqlUnique) column;
SQLIndexDefinition sqlIndexDefinition = mySqlKey.getIndexDefinition();
List<SQLSelectOrderByItem> sqlSelectOrderByItems = sqlIndexDefinition.getColumns();
List<String> keys = new ArrayList<>();
sqlSelectOrderByItems.forEach(keyItem -> {
if (keyItem.getExpr() instanceof SQLIdentifierExpr) {
SQLIdentifierExpr expr = (SQLIdentifierExpr) keyItem.getExpr();
keys.add("\"" + expr.getName().replace("`", "").toUpperCase() + "\"");
} else if (keyItem.getExpr() instanceof SQLMethodInvokeExpr) {
SQLMethodInvokeExpr invokeExpr = (SQLMethodInvokeExpr) keyItem.getExpr();
keys.add("\"" + invokeExpr.getMethodName().replace("`", "").toUpperCase() + "\"");
}
});
String indexName = "UNIQUE_" + tableName + "_" + StringUtils.join(keys, "_").replace("\"", "");
alterList.add("ALTER TABLE \"" + tableName + "\" ADD CONSTRAINT \"" + indexName + "\" UNIQUE(" + StringUtils.join(keys, ",") + ");");
} else if (column instanceof MySqlKey) {
MySqlKey mySqlKey = (MySqlKey) column;
SQLIndexDefinition sqlIndexDefinition = mySqlKey.getIndexDefinition();
List<SQLSelectOrderByItem> sqlSelectOrderByItems = sqlIndexDefinition.getColumns();
List<String> keys = new ArrayList<>();
sqlSelectOrderByItems.forEach(keyItem -> {
SQLIdentifierExpr expr = (SQLIdentifierExpr) keyItem.getExpr();
keys.add("\"" + expr.getName().replace("`", "").toUpperCase() + "\"");
});
String indexName = "IDX_" + tableName + "_" + StringUtils.join(keys, "_").replace("\"", "");
indexList.add("CREATE INDEX \"" + indexName + "\" ON \"" + tableName + "\"(" + StringUtils.join(keys, ",") + ");");
}
});
builder.replace(builder.length() - 2, builder.length() - 1, "");
builder.append(");\n");
creatTableList.add(builder.toString());
}
@Override
public void convertInsertStatement(MySqlInsertStatement statement) {
String tableName = statement.getTableName().toString().replace("`", "").toUpperCase();
StringBuilder builder = new StringBuilder("SET IDENTITY_INSERT \"");
builder.append(tableName).append("\" ON;");
insertList.add(builder.toString());
String sql = statement.toString().replace("`", "").replace("CURRENT_TIMESTAMP()", "CURRENT_TIMESTAMP").replace("current_timestamp()", "CURRENT_TIMESTAMP").replace("b'0'", "0").replace("b'1'", "1");
insertList.add(sql);
StringBuilder builder1 = new StringBuilder("SET IDENTITY_INSERT \"");
builder1.append(tableName).append("\" OFF;");
insertList.add(builder1.toString());
}
@Override
public void convertCreateIndexStatement(SQLCreateIndexStatement statement) {
String tableName = statement.getTableName().replace("`", "").toUpperCase();
SQLIndexDefinition sqlIndexDefinition = statement.getIndexDefinition();
List<SQLSelectOrderByItem> sqlSelectOrderByItems = sqlIndexDefinition.getColumns();
String type = null;
if (StringUtils.isNotBlank(sqlIndexDefinition.getType())) {
type = sqlIndexDefinition.getType().toUpperCase();
}
List<String> keys = new ArrayList<>();
sqlSelectOrderByItems.forEach(keyItem -> {
if (keyItem.getExpr() instanceof SQLIdentifierExpr) {
SQLIdentifierExpr expr = (SQLIdentifierExpr) keyItem.getExpr();
keys.add("\"" + expr.getName().replace("`", "").toUpperCase() + "\"");
} else if (keyItem.getExpr() instanceof SQLMethodInvokeExpr) {
SQLMethodInvokeExpr invokeExpr = (SQLMethodInvokeExpr) keyItem.getExpr();
keys.add("\"" + invokeExpr.getMethodName().replace("`", "").toUpperCase() + "\"");
}
});
if (StringUtils.isNotBlank(type) && "UNIQUE".equals(type)) {
String indexName = "UNIQUE_" + tableName + "_" + StringUtils.join(keys, "_").replace("\"", "");
indexList.add("ALTER TABLE \"" + tableName + "\" ADD CONSTRAINT \"" + indexName + "\" UNIQUE(" + StringUtils.join(keys, ",") + ");");
} else {
String indexName = "IDX_" + tableName + "_" + StringUtils.join(keys, "_").replace("\"", "");
indexList.add("CREATE INDEX \"" + indexName + "\" ON \"" + tableName + "\"(" + StringUtils.join(keys, ",") + ");");
}
}
@Override
public void convertUpdateStatement(MySqlUpdateStatement statement) {
String sql = statement.toString().replace("`", "").replace("CURRENT_TIMESTAMP()", "CURRENT_TIMESTAMP").replace("current_timestamp()", "CURRENT_TIMESTAMP").replace("b'0'", "0").replace("b'1'", "1");
updateList.add(sql);
}
@Override
public void convertDeleteStatement(MySqlDeleteStatement statement) {
String sql = statement.toString().replace("`", "").replace("b'0'", "0").replace("b'1'", "1");
updateList.add(sql);
}
@Override
public void convertAlterTableStatement(SQLAlterTableStatement statement) {
String tableName = statement.getTableName().toString().replace("`", "").toUpperCase();
statement.getItems().forEach(sqlAlterTableItem -> {
if (sqlAlterTableItem instanceof SQLAlterTableAddColumn) {
SQLAlterTableAddColumn addColumn = (SQLAlterTableAddColumn) sqlAlterTableItem;
addColumn.getColumns().forEach(addColumnItem -> {
StringBuilder builder = new StringBuilder("ALTER TABLE \"");
builder.append(tableName).append("\"");
builder.append(" ADD ").append(buildColumn(addColumnItem, null)).append(";\n");
SQLCharExpr commentSqlExpr = (SQLCharExpr) addColumnItem.getComment();
String columnName = addColumnItem.getColumnName().replace("`", "").replace("\"", "").toUpperCase();
String columnComment = null;
if (Objects.nonNull(commentSqlExpr)) {
columnComment = commentSqlExpr.getText();
}
if (StringUtils.isNotBlank(columnComment)) {
commentList.add("COMMENT ON COLUMN \"" + tableName + "\".\"" + columnName + "\" IS '" + columnComment + "';");
}
alterList.add(builder.toString());
});
} else if (sqlAlterTableItem instanceof MySqlAlterTableModifyColumn) {
MySqlAlterTableModifyColumn alterColumn = (MySqlAlterTableModifyColumn) sqlAlterTableItem;
SQLColumnDefinition definition = alterColumn.getNewColumnDefinition();
StringBuilder builder = new StringBuilder("ALTER TABLE \"");
builder.append(tableName).append("\"");
builder.append(" MODIFY ").append(buildColumn(definition, null)).append(";\n");
SQLCharExpr commentSqlExpr = (SQLCharExpr) definition.getComment();
String columnName = definition.getColumnName().replace("`", "").replace("\"", "").toUpperCase();
String columnComment = null;
if (Objects.nonNull(commentSqlExpr)) {
columnComment = commentSqlExpr.getText();
}
if (StringUtils.isNotBlank(columnComment)) {
commentList.add("COMMENT ON COLUMN \"" + tableName + "\".\"" + columnName + "\" IS '" + columnComment + "';");
}
alterList.add(builder.toString());
} else if (sqlAlterTableItem instanceof SQLAlterTableAddIndex) {
SQLAlterTableAddIndex addIndex = (SQLAlterTableAddIndex) sqlAlterTableItem;
SQLIndexDefinition sqlIndexDefinition = addIndex.getIndexDefinition();
List<SQLSelectOrderByItem> sqlSelectOrderByItems = sqlIndexDefinition.getColumns();
List<String> keys = new ArrayList<>();
sqlSelectOrderByItems.forEach(keyItem -> {
if (keyItem.getExpr() instanceof SQLIdentifierExpr) {
SQLIdentifierExpr expr = (SQLIdentifierExpr) keyItem.getExpr();
keys.add("\"" + expr.getName().replace("`", "").toUpperCase() + "\"");
} else if (keyItem.getExpr() instanceof SQLMethodInvokeExpr) {
SQLMethodInvokeExpr invokeExpr = (SQLMethodInvokeExpr) keyItem.getExpr();
keys.add("\"" + invokeExpr.getMethodName().replace("`", "").toUpperCase() + "\"");
}
});
String indexName = "IDX_" + tableName + "_" + StringUtils.join(keys, "_").replace("\"", "");
alterList.add("CREATE INDEX \"" + indexName + "\" ON \"" + tableName + "\"(" + StringUtils.join(keys, ",") + ");");
} else if (sqlAlterTableItem instanceof SQLAlterTableAddConstraint) {
SQLAlterTableAddConstraint addIndex = (SQLAlterTableAddConstraint) sqlAlterTableItem;
SQLConstraint sqlConstraint = addIndex.getConstraint();
if (sqlConstraint instanceof MySqlPrimaryKey) {
MySqlPrimaryKey mySqlPrimaryKey = (MySqlPrimaryKey) sqlConstraint;
List<SQLSelectOrderByItem> sqlSelectOrderByItems = mySqlPrimaryKey.getIndexDefinition().getColumns();
SQLIdentifierExpr expr = (SQLIdentifierExpr) sqlSelectOrderByItems.get(0).getExpr();
alterList.add("ALTER TABLE \"" + tableName + "\" ADD CONSTRAINT PRIMARY KEY(\"" + expr.getName().replace("`", "").toUpperCase() + "\");");
} else if (sqlConstraint instanceof MySqlUnique) {
MySqlUnique mySqlKey = (MySqlUnique) sqlConstraint;
SQLIndexDefinition sqlIndexDefinition = mySqlKey.getIndexDefinition();
List<SQLSelectOrderByItem> sqlSelectOrderByItems = sqlIndexDefinition.getColumns();
List<String> keys = new ArrayList<>();
sqlSelectOrderByItems.forEach(keyItem -> {
if (keyItem.getExpr() instanceof SQLIdentifierExpr) {
SQLIdentifierExpr expr = (SQLIdentifierExpr) keyItem.getExpr();
keys.add("\"" + expr.getName().replace("`", "").toUpperCase() + "\"");
} else if (keyItem.getExpr() instanceof SQLMethodInvokeExpr) {
SQLMethodInvokeExpr invokeExpr = (SQLMethodInvokeExpr) keyItem.getExpr();
keys.add("\"" + invokeExpr.getMethodName().replace("`", "").toUpperCase() + "\"");
}
});
String indexName = "UNIQUE_" + tableName + "_" + StringUtils.join(keys, "_").replace("\"", "");
alterList.add("ALTER TABLE \"" + tableName + "\" ADD CONSTRAINT \"" + indexName + "\" UNIQUE(\"" + StringUtils.join(keys, ",") + "\");");
} else if (sqlConstraint instanceof MySqlKey) {
MySqlKey mySqlKey = (MySqlKey) sqlConstraint;
SQLIndexDefinition sqlIndexDefinition = mySqlKey.getIndexDefinition();
List<SQLSelectOrderByItem> sqlSelectOrderByItems = sqlIndexDefinition.getColumns();
List<String> keys = new ArrayList<>();
sqlSelectOrderByItems.forEach(keyItem -> {
if (keyItem.getExpr() instanceof SQLIdentifierExpr) {
SQLIdentifierExpr expr = (SQLIdentifierExpr) keyItem.getExpr();
keys.add("\"" + expr.getName().replace("`", "").toUpperCase() + "\"");
} else if (keyItem.getExpr() instanceof SQLMethodInvokeExpr) {
SQLMethodInvokeExpr invokeExpr = (SQLMethodInvokeExpr) keyItem.getExpr();
keys.add("\"" + invokeExpr.getMethodName().replace("`", "").toUpperCase() + "\"");
}
});
String indexName = "IDX_" + tableName + "_" + StringUtils.join(keys, "_").replace("\"", "");
alterList.add("CREATE INDEX \"" + indexName + "\" ON \"" + tableName + "\"(" + StringUtils.join(keys, ",") + ");");
}
} else if (sqlAlterTableItem instanceof MySqlAlterTableChangeColumn) {
String columnName = ((MySqlAlterTableChangeColumn) sqlAlterTableItem).getColumnName().getSimpleName().replace("`", "").replace("\"", "").toUpperCase();
SQLColumnDefinition newColumn = ((MySqlAlterTableChangeColumn) sqlAlterTableItem).getNewColumnDefinition();
String newColumnName = newColumn.getColumnName().replace("`", "").replace("\"", "").toUpperCase();
alterList.add("ALTER TABLE \"" + tableName + "\" ALTER \"" + columnName + "\" RENAME TO \"" + newColumnName + "\";");
String builder = "ALTER TABLE \"" + tableName + "\"" +
" MODIFY " + buildColumn(newColumn, null) + ";\n";
SQLCharExpr commentSqlExpr = (SQLCharExpr) newColumn.getComment();
String columnComment = null;
if (Objects.nonNull(commentSqlExpr)) {
columnComment = commentSqlExpr.getText();
}
if (StringUtils.isNotBlank(columnComment)) {
commentList.add("COMMENT ON COLUMN \"" + tableName + "\".\"" + newColumnName + "\" IS '" + columnComment + "';");
}
alterList.add(builder);
}
});
}
@Override
public void convertRenameTableStatement(MySqlRenameTableStatement statement) {
MySqlRenameTableStatement.Item item = (MySqlRenameTableStatement.Item) statement.getItems().get(0);
String name = item.getName().getSimpleName().replace("`", "").toUpperCase();
String toName = item.getTo().getSimpleName().replace("`", "").toUpperCase();
alterList.add("ALTER TABLE \"" + name + "\" RENAME TO \"" + toName + "\";");
}
@Override
public void convertDropTableStatement(SQLDropTableStatement statement) {
String table = ((SQLIdentifierExpr) statement.getTableSources().get(0).getExpr()).getName().replace("`", "").toUpperCase();
alterList.add("DROP TABLE IF EXISTS \"" + table + "\";");
}
@Override
public void convertTruncateStatement(SQLTruncateStatement statement) {
String table = ((SQLIdentifierExpr) statement.getTableSources().get(0).getExpr()).getName().replace("`", "").toUpperCase();
alterList.add("TRUNCATE TABLE \"" + table + "\";");
}
private String buildColumn(SQLColumnDefinition definition, String increment) {
StringBuilder builder = new StringBuilder("");
String columnName = definition.getColumnName().replace("`", "").replace("\"", "").toUpperCase();
Boolean autoIncrement = definition.isAutoIncrement();
SQLDataTypeImpl dataType = (SQLDataTypeImpl) definition.getDataType();
String dataTypeName = dataType.getName().toUpperCase();
List<SQLExpr> sqlExprs = dataType.getArguments();
List<SQLColumnConstraint> constraints = definition.getConstraints();
if ("VARCHAR".equals(dataTypeName)) {
SQLIntegerExpr sqlIntegerExpr = (SQLIntegerExpr) sqlExprs.get(0);
builder.append("\"").append(columnName).append("\" ").append(dataTypeName).append("(").append(sqlIntegerExpr.getNumber()).append(")");
} else if ("TIMESTAMP".equals(dataTypeName) || "DATETIME".equals(dataTypeName)) {
builder.append("\"").append(columnName).append("\" ").append("TIMESTAMP(0)");
} else if ("BIT".equals(dataTypeName)) {
builder.append("\"").append(columnName).append("\" ").append("TINYINT");
} else if ("LONGTEXT".equals(dataTypeName)) {
builder.append("\"").append(columnName).append("\" ").append("TEXT");
} else if ("MEDIUMTEXT".equals(dataTypeName)) {
builder.append("\"").append(columnName).append("\" TEXT");
} else if ("DECIMAL".equals(dataTypeName)) {
SQLIntegerExpr precision = (SQLIntegerExpr) sqlExprs.get(0);
SQLIntegerExpr scale = (SQLIntegerExpr) sqlExprs.get(1);
builder.append("\"").append(columnName).append("\" ").append(" DECIMAL(").append(precision.getNumber()).append(", ").append(scale.getNumber()).append(")");
} else {
builder.append("\"").append(columnName).append("\" ").append(dataTypeName);
}
if (autoIncrement) {
if (StringUtils.isNotBlank(increment)) {
builder.append(" IDENTITY(").append(increment).append(",1)");
} else {
builder.append(" IDENTITY(1,1)");
}
}
SQLExpr sqlExpr = definition.getDefaultExpr();
if (Objects.nonNull(sqlExpr)) {
builder.append(" DEFAULT ");
if (sqlExpr instanceof SQLIntegerExpr) {
SQLIntegerExpr sqlIntegerExpr = (SQLIntegerExpr) sqlExpr;
builder.append(sqlIntegerExpr.getValue());
} else if (sqlExpr instanceof SQLBinaryExpr) {
SQLBinaryExpr sqlBinaryExpr = (SQLBinaryExpr) sqlExpr;
builder.append(sqlBinaryExpr.getValue());
} else if (sqlExpr instanceof SQLCurrentTimeExpr) {
builder.append("CURRENT_TIMESTAMP()");
} else if (sqlExpr instanceof SQLCharExpr) {
SQLCharExpr sqlCharExpr = (SQLCharExpr) sqlExpr;
builder.append("'").append(sqlCharExpr.getText()).append("'");
}
}
if (Objects.nonNull(constraints) && !constraints.isEmpty() && constraints.get(0) instanceof SQLNotNullConstraint) {
builder.append(" NOT NULL");
} else {
if (Objects.isNull(sqlExpr) || sqlExpr instanceof SQLNullExpr) {
builder.append(" NULL");
}
}
return builder.toString();
}
}