From 0492b77082c972c50e2e9050d91e07171a373190 Mon Sep 17 00:00:00 2001 From: wenshao Date: Tue, 17 Jul 2012 17:33:31 +0800 Subject: [PATCH] sql parser support mybatis --- .../sql/dialect/mysql/parser/MySqlLexer.java | 27 +++++++++++++++++- .../mysql/visitor/MySqlOutputVisitor.java | 3 +- .../dialect/oracle/parser/OracleLexer.java | 17 ++++++++++- .../com/alibaba/druid/sql/parser/Lexer.java | 25 +++++++++++++++-- .../alibaba/druid/bvt/sql/MybatisTest.java | 28 +++++++++++++++++++ .../alibaba/druid/bvt/sql/MybatisTest2.java | 28 +++++++++++++++++++ 6 files changed, 122 insertions(+), 6 deletions(-) create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/MybatisTest.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/MybatisTest2.java diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlLexer.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlLexer.java index f4e3c300e0..ea624747e1 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlLexer.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlLexer.java @@ -63,7 +63,7 @@ public class MySqlLexer extends Lexer { public void scanVariable() { final char first = ch; - if (ch != '@' && ch != ':' && ch != '#') { + if (ch != '@' && ch != ':' && ch != '#' && ch != '$') { throw new SQLParseException("illegal variable"); } @@ -104,6 +104,31 @@ public class MySqlLexer extends Lexer { stringVal = symbolTable.addSymbol(buf, np, sp, hash); token = Token.VARIANT; + } else if (buf[bp + 1] == '{') { + ++bp; + ++sp; + char ch; + for (;;) { + ch = buf[++bp]; + + if (ch == '}') { + sp++; + ch = buf[++bp]; + break; + } else if (ch == EOI) { + throw new SQLParseException("illegal identifier"); + } + + hash = 31 * hash + ch; + + sp++; + continue; + } + + this.ch = buf[bp]; + + stringVal = symbolTable.addSymbol(buf, np, sp, hash); + token = Token.VARIANT; } else { for (;;) { ch = buf[++bp]; diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java index 94da69584b..29a75b2a98 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java @@ -494,7 +494,8 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV if (x.isGlobal()) { print("@@global."); } else { - if ((!x.getName().startsWith("@")) && (!x.getName().equals("?"))) { + String varName = x.getName(); + if ((!varName.startsWith("@")) && (!varName.equals("?")) && (!varName.startsWith("#")) && (!varName.startsWith("$"))) { print("@@"); } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleLexer.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleLexer.java index 658a20a017..1065cbcf2e 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleLexer.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleLexer.java @@ -87,7 +87,7 @@ public class OracleLexer extends Lexer { return; } - if (ch != ':' && ch != '#') { + if (ch != ':' && ch != '#' && ch != '$') { throw new SQLParseException("illegal variable"); } @@ -98,12 +98,19 @@ public class OracleLexer extends Lexer { char ch; boolean quoteFlag = false; + boolean mybatisFlag = false; if (buf[bp + 1] == '"') { hash = 31 * hash + '"'; bp++; sp++; quoteFlag = true; + } else if (buf[bp + 1] == '{') { + hash = 31 * hash + '"'; + bp++; + sp++; + mybatisFlag = true; } + for (;;) { ch = buf[++bp]; @@ -116,6 +123,7 @@ public class OracleLexer extends Lexer { sp++; continue; } + if (quoteFlag) { if (ch != '"') { throw new SQLParseException("syntax error"); @@ -123,6 +131,13 @@ public class OracleLexer extends Lexer { hash = 31 * hash + '"'; ++bp; sp++; + } else if (mybatisFlag) { + if (ch != '}') { + throw new SQLParseException("syntax error"); + } + hash = 31 * hash + '"'; + ++bp; + sp++; } this.ch = buf[bp]; diff --git a/src/main/java/com/alibaba/druid/sql/parser/Lexer.java b/src/main/java/com/alibaba/druid/sql/parser/Lexer.java index 15a58a62ee..de8fe9813d 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/Lexer.java +++ b/src/main/java/com/alibaba/druid/sql/parser/Lexer.java @@ -205,9 +205,13 @@ public class Lexer { if (isWhitespace(ch)) { scanChar(); continue; - }// QS_TODO skip comment + } + + if (ch == '$' && buf[bp + 1] == '{') { + scanVariable(); + return; + } - // QS_TODO id may start from digit if (isFirstIdentifierChar(ch)) { if (ch == 'N') { if (buf[bp + 1] == '\'') { @@ -571,7 +575,7 @@ public class Lexer { public void scanVariable() { final char first = ch; - if (ch != '@' && ch != ':' && ch != '#') { + if (ch != '@' && ch != ':' && ch != '#' && ch != '$') { throw new SQLParseException("illegal variable"); } @@ -581,11 +585,17 @@ public class Lexer { sp = 1; char ch; + boolean mybatisFlag = false; if (buf[bp + 1] == '@') { ch = buf[++bp]; hash = 31 * hash + ch; sp++; + } else if (buf[bp + 1] == '{') { + hash = 31 * hash + '"'; + bp++; + sp++; + mybatisFlag = true; } for (;;) { @@ -600,6 +610,15 @@ public class Lexer { sp++; continue; } + + if (mybatisFlag) { + if (ch != '}') { + throw new SQLParseException("syntax error"); + } + hash = 31 * hash + '"'; + ++bp; + sp++; + } this.ch = buf[bp]; diff --git a/src/test/java/com/alibaba/druid/bvt/sql/MybatisTest.java b/src/test/java/com/alibaba/druid/bvt/sql/MybatisTest.java new file mode 100644 index 0000000000..e403c518f1 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/MybatisTest.java @@ -0,0 +1,28 @@ +package com.alibaba.druid.bvt.sql; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.util.JdbcUtils; + + +public class MybatisTest extends TestCase { + private String sql = "select * from t where id = #{id}"; + + public void test_mysql() throws Exception { + Assert.assertEquals("SELECT *\nFROM t\nWHERE id = #{id}", SQLUtils.format(sql, JdbcUtils.MYSQL)); + } + + public void test_oracle() throws Exception { + Assert.assertEquals("SELECT *\nFROM t\nWHERE id = #{id}", SQLUtils.format(sql, JdbcUtils.ORACLE)); + } + + public void test_postgres() throws Exception { + Assert.assertEquals("SELECT *\nFROM t\nWHERE id = #{id}", SQLUtils.format(sql, JdbcUtils.POSTGRESQL)); + } + + public void test_sql92() throws Exception { + Assert.assertEquals("SELECT *\nFROM t\nWHERE id = #{id}", SQLUtils.format(sql, null)); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/MybatisTest2.java b/src/test/java/com/alibaba/druid/bvt/sql/MybatisTest2.java new file mode 100644 index 0000000000..df44ae013b --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/MybatisTest2.java @@ -0,0 +1,28 @@ +package com.alibaba.druid.bvt.sql; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.util.JdbcUtils; + + +public class MybatisTest2 extends TestCase { + private String sql = "select * from t where id = ${id}"; + + public void test_mysql() throws Exception { + Assert.assertEquals("SELECT *\nFROM t\nWHERE id = ${id}", SQLUtils.format(sql, JdbcUtils.MYSQL)); + } + + public void test_oracle() throws Exception { + Assert.assertEquals("SELECT *\nFROM t\nWHERE id = ${id}", SQLUtils.format(sql, JdbcUtils.ORACLE)); + } + + public void test_postgres() throws Exception { + Assert.assertEquals("SELECT *\nFROM t\nWHERE id = ${id}", SQLUtils.format(sql, JdbcUtils.POSTGRESQL)); + } + + public void test_sql92() throws Exception { + Assert.assertEquals("SELECT *\nFROM t\nWHERE id = ${id}", SQLUtils.format(sql, null)); + } +}