前段时间,研究数据库迁移工作,使用Powerdesigner实现了数据库对象之间的转换,但是由于项目中使用了大量的存储过程、函数和触发器等,想着怎么实现这些代码的迁移,网上搜了一通,大概有两个工具(SQLWays和SwisSQL,具体可以百度),后来也使用了一种工具,但是转换效果不是特别好,需要手工重新修改。这些都是后话;还有一个思路,就是使用javaCC进行在词法语法级别进行转换。首先将T-SQL进行词法分析,语法分析,最后按照P-SQL语法规则进行重新生成。由于时间进度和难度,我也只是简单识别了一些语句,下面写个简单例子,以后有时间继续研究。javaCC的安装不再叙述,附件中是安装文件和示例;
需要转换的语句:
CREATE FUNC test(@pdata varchar(20), @pint int(10)) RETURN varchar(30)
在Eclipse建立一个文件sql.jj,注意规则里面的符号都是全英文状态下的
/**
* JavaCC file
*/
options {
JDK_VERSION = "1.5";
STATIC = true ; //生成非静态类
LOOKAHEAD=1;//向前看2个字母,消除歧义用的
DEBUG_PARSER = true;//以debug形式生成,便于调试
}
PARSER_BEGIN(eg1)
package cn.heu.javacct.sql;
import java.lang.StringBuffer;
import java.io.StringReader;
import java.io.Reader;
public class eg1 {
private static StringBuffer sqlSB;
public eg1(String s){
this((Reader)(new StringReader(s)));
sqlSB = new StringBuffer();
}
public String getSQL()
{
return sqlSB.toString();
}
public String convert(){
String temp="";
try
{
temp= convertSQL();
}
catch(Exception e)
{
e.printStackTrace();
}
return temp;
}
public static void main(String args[]) throws ParseException {
eg1 parser =null;
try
{
String query = " -- "+
" CREATE FUNC test(@pdata varchar(20),@pint int(10)) RETURN varchar(30) ";
parser = new eg1(query);
// parser.convert();
System.out.println("OLDSQL:"+query);
System.out.println("SQL:"+ parser.convert());
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
PARSER_END(eg1)
SKIP :
{
" "
| "\r"
| "\t"
| "\n"
| "--"
}
TOKEN:/* ms SQL keywords*/
{
< CREATE:" CREATE "|" create " >
|< ALTER:" ALTER "|" alter " >
|< FROM : " from " >
|< FUNCNAME:<FUNCNAME> >
|< FUNCTION :" FUNC "|" FUNCTION "|" func "|" function " >
|< PROCEDURE:" PROCEDURE "|" PROC "|" procedure "|" proc " >
|< RETURN:" RETURN "|" return " >
|< _begin:" begin "|" BEGIN " >
|< _end:" end "|" END " >
|< #FUNCNAME :(["0" - "9","A" - "Z","a" - "z"])+ >
}
TOKEN:/* ms SQL datatype */
{
< VARCHAR:"varchar("<NUM>")" >
|< INT:"int"<NUM> >
|< #NUM:(["0" - "9"])+>
}
TOKEN:
{
<papams:"("(<PARAM>|<PARAM>","<PARAM>|<PARAM>(","<PARAM>",")+<PARAM>)")" >
|<#PARAM:<p_data>" "<p_type>>
|<#p_data:(["0" - "9","A" - "Z","a" - "z","@"])+>
|<#p_type:<p_varchar>|<p_int>>
|<#p_varchar:"varchar("<p_NUM>")">
|<#p_int:"int("<p_NUM>")" >
|<#p_NUM:(["0" - "9"])+>
}
String convertSQL():{
Token t;
String temp="";
StringBuffer sb=new StringBuffer();
}
{
(
<CREATE>
<FUNCTION>
t=<FUNCNAME>
{
sb.append(" create or replace function " );
sb.append(" "+t.image+" ");
}
t= <papams>
{
sb.append(t.image.replace("@",""));
}
t= <RETURN>
{
sb.append(" "+t.image+" ");
}
t=<VARCHAR>
{
sb.append(" "+t.image+" ");
}
)*
{
return sb.toString();
}
}
建立完文件后,javaCC会自动生成相关的类
如下:
打开eg1.java,执行即可;
OLDSQL: -- CREATE FUNC test(@pdata varchar(20),@pint int(10)) RETURN varchar(30)
Call: convertSQL
Consumed token: <<CREATE>: " CREATE " at line 1 column 6>
Consumed token: <<FUNCTION>: " FUNC " at line 1 column 15>
Consumed token: <<FUNCNAME>: "test" at line 1 column 22>
Consumed token: <<papams>: "(@pdata varchar(20),@pint int(10))" at line 1 column 26>
Consumed token: <<RETURN>: " RETURN " at line 1 column 62>
Consumed token: <<VARCHAR>: "varchar(30)" at line 1 column 71>
Return: convertSQL
SQL: create or replace function test (pdata varchar(20),pint int(10)) RETURN varchar(30)
可见已经正常识别了!
如需扩展,还需深入研究,看见官方例子,该软件还是很强大的