Oracle建表语句修改为MySQL的建表语句,在提供Oracle连接和不使用连接的情况下实现方式略有不同:
- 有原始环境,可以将所有需要的信息进行获取,然后拼接生成语法
- 没有原始环境,使用Druid解析Oracle语法,并定制转换规则生成对应的MySQL语法
本文主要是对没有原始环境的Oracle导出的ddl文件进行转换,有原始环境的在线转换另开篇介绍。
基本实现步骤是解析语法生成对应的statement,并对statement实现定制,本省Druid能够使用定制的Visitor来实现相关的定制操作,但是Oracle导出的ddl文件中,主键是使用单独的语句导出。而在我们转换的DDL的要求中,建表语句必须要携带主键信息,否则创建失败,就不能使用Visitor。没有这种硬性要求的小伙伴们可以尝试下使用visitor进行定制,实现会更清晰明朗。
-
文件读取,该部分没有啥好多说的,读取文件到内存中
try (InputStreamReader fReader = new InputStreamReader(new FileInputStream(file), Constants.BASIC.FILE_DEFAULT_CHARSET); BufferedReader reader = new BufferedReader(fReader)) { String temp; while ((temp = reader.readLine()) != null) { boolean add = true; for (String s : blackList) { if (temp.startsWith(s)) { add = false; break; } } if (add) { sb.append(temp).append(Constants.BASIC.LINE_SPLIT); } } } catch (IOException e) { e.printStackTrace(); }
-
使用Druid进行解析生成对应的statement列表
List<SQLStatement> statements = SQLUtils.parseStatements(src.toUpperCase(), "oracle");
-
对列表的Statement类型做判断,保留ddl语句,并且将属于同一个表的statement存放到一起
Map<String, List<SQLStatement>> tbStmt = new HashMap<>(); for (SQLStatement statement : statements) { String tbSchema; if (statement instanceof OracleCreateTableStatement) { tbSchema = ((OracleCreateTableStatement) statement).getTableSource().getName().toString(); } else if (statement instanceof SQLAlterTableStatement) { String tbName = ((SQLAlterTableStatement) statement).getTableName(); String dbname = ((SQLAlterTableStatement) statement).getSchema(); tbSchema = (dbname + "." + tbName).replaceAll(" ", ""); } else if (statement instanceof OracleCreateIndexStatement) { String tbName = ((SQLCreateIndexStatement) statement).getTableName(); String dbname = ((SQLCreateIndexStatement) statement).getSchema(); tbSchema = (dbname + "." + tbName).replaceAll(" ", ""); } else if (statement instanceof SQLCommentStatement) { SQLPropertyExpr expr = (SQLPropertyExpr) ((SQLCommentStatement) statement).getOn().getExpr(); if (expr.getOwner().toString().contains(".")) { tbSchema = expr.getOwner().toString(); } else { tbSchema = expr.toString(); } } else { continue; } if (null == tbStmt.get(tbSchema)) { List<SQLStatement> tl = new ArrayList<>(); tl.add(statement); tbStmt.put(tbSchema, tl); } else { tbStmt.get(tbSchema).add(statement); }
-
对每个表的ddl进行定制转换,并转换成对应的MySQL建表对象
List<MySqlCreateTableStatement> mcs = new ArrayList<>(); List<String> lostPrimaryKeyTables = new ArrayList<>(); for (Map.Entry<String, List<SQLStatement>> entry : stmtMap.entrySet()) { MySqlCreateTableStatement mc = new MySqlCreateTableStatement(); List<SQLTableElement> mte = new ArrayList<>(); List<SQLTableElement> autoIncrements = new ArrayList<>(); String tbName = "", dbName = ""; for (SQLStatement stmt : entry.getValue()) { if (stmt instanceof OracleCreateTableStatement) { OracleCreateTableStatement db2cts = (OracleCreateTableStatement) stmt; List<SQLTableElement> tes = db2cts.getTableElementList(); tbName = ((SQLPropertyExpr) db2cts.getName()).getName(); dbName = ((SQLPropertyExpr) db2cts.getName()).getOwnernName(); for (SQLTableElement te : tes) { if (te instanceof SQLColumnDefinition) { ((SQLColumnDefinition) te).setDbType(JdbcConstants.MYSQL); ((SQLColumnDefinition) te) .setDataType(SQLTransformUtils.transformOracleToMySql(((SQLColumnDefinition) te).getDataType())); SQLIdentifierExpr name = (SQLIdentifierExpr) ((SQLColumnDefinition) te).getName(); name.setName(Constants.BASIC.MYSQL_ENCLOSE + name.getName() + Constants.BASIC.MYSQL_ENCLOSE); mte.add(te); if (((SQLColumnDefinition) te).isAutoIncrement()) { autoIncrements.add(te); } } } } else if (stmt instanceof SQLAlterTableStatement) { SQLAlterTableStatement db2ats = (SQLAlterTableStatement) stmt; List<SQLAlterTableItem> items = db2ats.getItems(); for (SQLAlterTableItem item : items) { if (item instanceof SQLAlterTableAddConstraint) { SQLAlterTableAddConstraint ac = (SQLAlterTableAddConstraint) item; SQLConstraint constraint = ac.getConstraint(); if (constraint instanceof OraclePrimaryKey) { OraclePrimaryKey pk = (OraclePrimaryKey) constraint; MySqlPrimaryKey mp = new MySqlPrimaryKey(); List<SQLSelectOrderByItem> tt = pk.getColumns(); for (SQLSelectOrderByItem t : tt) { SQLIdentifierExpr e = (SQLIdentifierExpr) t.getExpr(); e.setName(Constants.BASIC.MYSQL_ENCLOSE + e.getName() + Constants.BASIC.MYSQL_ENCLOSE); } mp.getColumns().addAll(pk.getColumns()); mte.add(mp); } else if (constraint instanceof OracleUnique) { OracleUnique pk = (OracleUnique) constraint; MySqlPrimaryKey mp = new MySqlPrimaryKey(); List<SQLSelectOrderByItem> tt = pk.getColumns(); for (SQLSelectOrderByItem t : tt) { SQLIdentifierExpr e = (SQLIdentifierExpr) t.getExpr(); e.setName(Constants.BASIC.MYSQL_ENCLOSE + e.getName() + Constants.BASIC.MYSQL_ENCLOSE); } mp.getColumns().addAll(pk.getColumns()); mte.add(mp); } else { LOG.error("Lost parse [" + constraint.getClass() + "],statement is " + constraint); } } else { LOG.error("Lost parse [" + item.getClass() + "],statement is " + item); } } } else if (stmt instanceof OracleCreateIndexStatement) { SQLCreateIndexStatement db2cis = (OracleCreateIndexStatement) stmt; List<SQLSelectOrderByItem> items = db2cis.getItems(); for (SQLSelectOrderByItem item : items) { item.setType(null); SQLIdentifierExpr e = (SQLIdentifierExpr) item.getExpr(); e.setName(Constants.BASIC.MYSQL_ENCLOSE + e.getName() + Constants.BASIC.MYSQL_ENCLOSE); } if (null != db2cis.getType() && db2cis.getType().toLowerCase().equals("unique")) { MySqlUnique unique = new MySqlUnique(); unique.getColumns().addAll(db2cis.getItems()); mte.add(unique); } else { MySqlTableIndex index = new MySqlTableIndex(); index.getColumns().addAll(db2cis.getItems()); mte.add(index); } } //else if (stmt instanceof SQLCommentStatement) { // LOG.debug("no body");} else { LOG.error("Lost parse [" + stmt.getClass() + "],statement is " + stmt); } } mc.getTableElementList().addAll(mte); MySqlUserName name = new MySqlUserName(); name.setUserName(Constants.BASIC.MYSQL_ENCLOSE + dbName.replaceAll(" ", "") + Constants.BASIC.MYSQL_ENCLOSE + '.' + Constants.BASIC.MYSQL_ENCLOSE + tbName.replaceAll(" ", "") + Constants.BASIC.MYSQL_ENCLOSE); mc.setName(name); mcs.add(mc); }
-
剩下的就是将生成的DDL输出成文件即可,该实现并未将注释纳入,需要的小伙伴自行添加
-
关于类型转换,Druid的实现
SQLTransformUtils.transformOracleToMySql(((SQLColumnDefinition) te).getDataType());
具体的实现可以查看源码。