|
最近从上一个项目里面出来,开始了新的项目的工作和学习。在这承上启下之际,花了点时间反思之前学到的东西,又结合新项目知识的学习,做了一个用javascript解析SQL语句的小程序。
在上一个项目的重要工作就是写SQL语句,insert,delete和update语句为主,通过配置数据库中的记录, 来展现用户可定制的页面显示。其中很大一部分工作花费在对SQL语句的检查中。 根据数据库表结构的逻辑关系,我们必须保证输入的数据是有效的,并且是有意义的。为此,我们专门有一个checklist的文档来描述。
当时就很想做一个自动化的工具,每次写完脚本以后,往工具里面一传,马上就能出来个report,说明哪哪不对了,哪个checklist没过了,一目了然。
但是总是太懒惰了,给自己找各种各样的借口,最终也没有去做。
现在的新项目用的是Dojo开发的RIA应用,第一次接触客户端层的开发,相对于传统的J2EE服务器端的开发,根本就是一头雾水。 经历了整整两周时间的混乱,终于多少对javascript的客户端开发有了一定的了解。
于是就想到了为前一个项目做点贡献,利用dojo/javascript开发一个解析SQL语句的web小工具。
技术难点:
1. 利用正则表达式匹配SQL语句。
2. 能够解析出scripts中的注释及COMMITS语句并提取出。
代码:
1. validateSQL函数中定义了匹配SQL语句的正则表达式,并对每一种SQL分别处理,并返回结果。
2. splitSqlArray通过分号来区分语句,同时去掉所有注释。 要注意的是,SQL的value中有可能包含分号, 需要把这种情况考虑到。
validateSQL: function(content) {
var insertReg = /INSERT[\s+\n+]+INTO[\s+\n+]+\S+[\s*\n*]*\([\S*\s*\n*]+\)[\s*\n*]+VALUES[\s*\n*]*\([\S*\s*\n*]+\)/;
var updateReg = /UPDATE[\s+\n+]+\S+[\s+\n+]+SET[\S*\s*\n*]+(WHERE[\S*\s*\n*]+)?/;
var deleteReg = /DELETE[\s+\n+]+FROM[\s+\n+]+\S+[\s+\n+]+(WHERE[\S*\s*\n*]+)?/;
var commitReg = /COMMIT;/;
var scriptArray = Util.splitSqlArray(content);
var result = new Array();
for(var i = 0; i <scriptArray.length; i++) {
if(scriptArray.word.trim() == "") continue;
var script = scriptArray.word.trim();
if((stat = insertReg.exec(script)) != null) {
sTable = stat[0].substring(stat[0].indexOf("INTO") + 4, stat[0].indexOf("(")).trim();
var item = [scriptArray.rowid, sTable, "INSERT", "NA", 1, "LOW", script];
} else if((stat = updateReg.exec(script))!= null) {
sTable = stat[0].substring(stat[0].indexOf("UPDATE") + 6, stat[0].indexOf("SET")).trim();
if(stat[0].indexOf("WHERE") > 0) {
sCond = stat[0].substring(stat[0].indexOf("WHERE") + 5).trim();
item = [scriptArray.rowid, sTable, "UPDATE", sCond, 100, "MEDIUM", script];
} else {
item = [scriptArray.rowid, sTable, "UPDATE", "NA", 100, "HIGH", "You don't have a where clause!"];
}
} else if((stat = deleteReg.exec(script))!= null) {
sTable = stat[0].substring(stat[0].indexOf("FROM") + 4, stat[0].indexOf("WHERE")).trim();
if(stat[0].indexOf("WHERE") > 0) {
sCond = stat[0].substring(stat[0].indexOf("WHERE") + 5).trim();
item = [scriptArray.rowid, sTable, "DELETE", sCond, 100, "MEDIUM", script];
} else {
item = [scriptArray.rowid, sTable, "UPDATE", "NA", 100, "HIGH", "You don't have a where clause!"];
}
} else {
item = null;
}
if(item != null) result[result.length] = item;
}
return result;
}
splitSqlArray:function(content) {
var count = 1;
var started = false;
var result = new Array();
for(var i = 0; i < content.length; i++) {
var cChar = content.charAt(i);
if(cChar == '-') {
if(content.charAt(i + 1) == '-') {
while(true) {
cChar = content[++i];
if(cChar == '\n') {
count++;
break;
}
}
continue;
}
}
if(cChar == '\n'){
count++;
continue;
}
if(!started) {
var iRowid = count;
var sWord = new Array();
sWord[sWord.length] = cChar;
started = true;
} else if(cChar == "'"){
sWord[sWord.length] = cChar;
while(true) {
cChar = content[++i];
sWord[sWord.length] = cChar;
if(cChar == "'") break;
}
} else if(cChar == ";") {
result[result.length] = {rowid : iRowid, word:(sWord.join(""))};
started = false;
} else {
sWord[sWord.length] = cChar;
}
}
return result;
}
测试用的SQL:
-- ######### INSERTs for CLSFDWAPS on server S ######### --
-- ### PROV.APPROVED_FIELDS_MAPPING
INSERT INTO PROV.APPROVED_FIELDS_MAPPING (APP_CODE, GROUP_NO, INPUT_FORM_FIELD, INPUT_FORM_VAL, "TYPE")
VALUES ('CLSFDWAPS', 01, 'Region', 'Region_AseanIsa', 'INTRANET');
INSERT INTO PROV.APPROVED_FIELDS_MAPPING (APP_CODE, GROUP_NO, INPUT_FORM_FIELD, INPUT_FORM_VAL, "TYPE")
VALUES ('CLSFDWAPS', 02, 'Region', 'Region_AusNz', 'INTRANET');
INSERT INTO PROV.APPROVED_FIELDS_MAPPING (APP_CODE, GROUP_NO, INPUT_FORM_FIELD, INPUT_FORM_VAL, "TYPE")
VALUES ('CLSFDWAPS', 03, 'Region', 'Region_Gcg', 'INTRANET');
-- here is what I am testing.
-- again still test.
UPDATE PROV.APPROVED_FIELDS_MAPPING SET APP_CODE='CLSFDWAPS';
commit;
得到的结果:
其实很多内容都还没有考虑,比方说checklist,现在只考虑了一种,就是update/delete没有where语句。
日后慢慢改吧,如果有时间的话。 |
|