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 8a7046af26..425ba50e1a 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 @@ -534,4 +534,87 @@ public class MySqlLexer extends Lexer { private boolean isIdentifierChar(char c) { return c != '#' && CharTypes.isIdentifierChar(c); } + + public void scanNumber() { + mark = pos; + + if (ch == '-') { + bufPos++; + ch = charAt(++pos); + } + + for (;;) { + if (ch >= '0' && ch <= '9') { + bufPos++; + } else { + break; + } + ch = charAt(++pos); + } + + boolean isDouble = false; + + if (ch == '.') { + if (charAt(pos + 1) == '.') { + token = Token.LITERAL_INT; + return; + } + bufPos++; + ch = charAt(++pos); + isDouble = true; + + for (;;) { + if (ch >= '0' && ch <= '9') { + bufPos++; + } else { + break; + } + ch = charAt(++pos); + } + } + + if (ch == 'e' || ch == 'E') { + bufPos++; + ch = charAt(++pos); + + if (ch == '+' || ch == '-') { + bufPos++; + ch = charAt(++pos); + } + + for (;;) { + if (ch >= '0' && ch <= '9') { + bufPos++; + } else { + break; + } + ch = charAt(++pos); + } + + isDouble = true; + } + + if (isDouble) { + token = Token.LITERAL_FLOAT; + } else { + if (isFirstIdentifierChar(ch) && !(ch == 'b' && bufPos == 1 && charAt(pos - 1) == '0')) { + bufPos++; + for (;;) { + ch = charAt(++pos); + + if (!isIdentifierChar(ch)) { + break; + } + + bufPos++; + continue; + } + + stringVal = addSymbol(); + token = Token.IDENTIFIER; + } else { + token = Token.LITERAL_INT; + } + } + } } 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 12dbae40fb..7b6e57a0f1 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/Lexer.java +++ b/src/main/java/com/alibaba/druid/sql/parser/Lexer.java @@ -373,7 +373,7 @@ public class Lexer { return; case '.': scanChar(); - if (isDigit(ch)) { + if (isDigit(ch) && !isFirstIdentifierChar(charAt(pos - 2))) { unscan(); scanNumber(); return; diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/BigSqlTest.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/BigSqlTest.java index 9483575a40..6bcbba19df 100644 --- a/src/test/java/com/alibaba/druid/bvt/filter/wall/BigSqlTest.java +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/BigSqlTest.java @@ -13,7 +13,7 @@ public class BigSqlTest extends TestCase { String sql = "SELECT c from sbtest where id=0"; for (int i = 0; i < 10000; i++) { - sql += "or id=0"; + sql += " or id=0"; } WallConfig config = new WallConfig(); Assert.assertTrue(WallUtils.isValidateMySql(sql, config)); @@ -23,7 +23,7 @@ public class BigSqlTest extends TestCase { String sql = "SELECT c from sbtest where id=0"; for (int i = 0; i < 10000; i++) { - sql += "and id=0"; + sql += " and id=0"; } WallConfig config = new WallConfig(); Assert.assertTrue(WallUtils.isValidateMySql(sql, config)); diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/IdentifierTest.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/IdentifierTest.java new file mode 100644 index 0000000000..560f420133 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/IdentifierTest.java @@ -0,0 +1,150 @@ +/* + * Copyright 1999-2011 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.druid.bvt.sql.mysql; + +import java.util.List; + +import org.junit.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser; +import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor; +import com.alibaba.druid.sql.parser.SQLStatementParser; + +public class IdentifierTest extends TestCase { + + public void test_0() throws Exception { + String sql = "SELECT t.1c FROM tab t"; + + SQLStatementParser parser = new MySqlStatementParser(sql); + List stmtList = parser.parseStatementList(); + + String text = output(stmtList); + + Assert.assertEquals("SELECT t.1c\nFROM tab t;", text); + } + + public void test_1() throws Exception { + String sql = "SELECT tid,seller_nick,jdp_response from 2df1479e96cb4ac8b57f2502b5425bb5"; + + SQLStatementParser parser = new MySqlStatementParser(sql); + List stmtList = parser.parseStatementList(); + + String text = output(stmtList); + + Assert.assertEquals("SELECT tid, seller_nick, jdp_response\nFROM 2df1479e96cb4ac8b57f2502b5425bb5;", text); + } + + public void test_2() throws Exception { + String sql = "SELECT 1 ^ 1"; + + SQLStatementParser parser = new MySqlStatementParser(sql); + List stmtList = parser.parseStatementList(); + + String text = output(stmtList); + + Assert.assertEquals("SELECT 1 ^ 1;", text); + } + + public void test_3() throws Exception { + String sql = "SELECT 1 ^ 0"; + + SQLStatementParser parser = new MySqlStatementParser(sql); + List stmtList = parser.parseStatementList(); + + String text = output(stmtList); + + Assert.assertEquals("SELECT 1 ^ 0;", text); + } + + public void test_4() throws Exception { + String sql = "SELECT 1 << 2"; + + SQLStatementParser parser = new MySqlStatementParser(sql); + List stmtList = parser.parseStatementList(); + + String text = output(stmtList); + + Assert.assertEquals("SELECT 1 << 2;", text); + } + + public void test_5() throws Exception { + String sql = "SELECT 4 >> 2"; + + SQLStatementParser parser = new MySqlStatementParser(sql); + List stmtList = parser.parseStatementList(); + + String text = output(stmtList); + + Assert.assertEquals("SELECT 4 >> 2;", text); + } + + public void test_6() throws Exception { + String sql = "SELECT 5 & ~1"; + + SQLStatementParser parser = new MySqlStatementParser(sql); + List stmtList = parser.parseStatementList(); + + String text = output(stmtList); + + Assert.assertEquals("SELECT 5 & ~1;", text); + } + + public void test_7() throws Exception { + String sql = "SELECT BIT_COUNT(29), BIT_COUNT(b'101010');"; + + SQLStatementParser parser = new MySqlStatementParser(sql); + List stmtList = parser.parseStatementList(); + + String text = output(stmtList); + + Assert.assertEquals("SELECT BIT_COUNT(29), BIT_COUNT(b'101010');", text); + } + + public void test_8() throws Exception { + String sql = "SET @v2 = CAST(0b1000001 AS UNSIGNED), @v3 = 0b1000001+0;"; + + SQLStatementParser parser = new MySqlStatementParser(sql); + List stmtList = parser.parseStatementList(); + + String text = output(stmtList); + + Assert.assertEquals("SET @v2 = CAST(b'1000001' AS UNSIGNED), @v3 = b'1000001' + 0;", text); + } + + public void test_9() throws Exception { + String sql = "SELECT b+0, BIN(b+0), OCT(b+0), HEX(b+0) FROM t;"; + + SQLStatementParser parser = new MySqlStatementParser(sql); + List stmtList = parser.parseStatementList(); + + String text = output(stmtList); + + Assert.assertEquals("SELECT b + 0, BIN(b + 0), OCT(b + 0), HEX(b + 0)\nFROM t;", text); + } + + private String output(List stmtList) { + StringBuilder out = new StringBuilder(); + + for (SQLStatement stmt : stmtList) { + stmt.accept(new MySqlOutputVisitor(out)); + out.append(";"); + } + + return out.toString(); + } +}