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 3b4cda71c8..2a3987a654 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 @@ -280,128 +280,7 @@ public class MySqlLexer extends Lexer { } protected final void scanString() { - { - boolean hasSpecial = false; - int startIndex = pos + 1; - int endIndex = -1; // text.indexOf('\'', startIndex); - for (int i = startIndex; i < text.length(); ++i) { - final char ch = text.charAt(i); - if (ch == '\\') { - hasSpecial = true; - continue; - } - if (ch == '\'') { - endIndex = i; - break; - } - } - - if (endIndex == -1) { - throw new ParserException("unclosed str"); - } - - String stringVal = subString(startIndex, endIndex - startIndex); - // hasSpecial = stringVal.indexOf('\\') != -1; - - if (!hasSpecial) { - this.stringVal = stringVal; - int pos = endIndex + 1; - char ch = charAt(pos); - if (ch != '\'') { - this.pos = pos; - this.ch = ch; - token = LITERAL_CHARS; - return; - } - } - } - - mark = pos; - boolean hasSpecial = false; - for (;;) { - if (isEOF()) { - lexError("unclosed.str.lit"); - return; - } - - ch = charAt(++pos); - - if (ch == '\\') { - scanChar(); - if (!hasSpecial) { - initBuff(bufPos); - arraycopy(mark + 1, buf, 0, bufPos); - hasSpecial = true; - } - - switch (ch) { - case '0': - putChar('\0'); - break; - case '\'': - putChar('\''); - break; - case '"': - putChar('"'); - break; - case 'b': - putChar('\b'); - break; - case 'n': - putChar('\n'); - break; - case 'r': - putChar('\r'); - break; - case 't': - putChar('\t'); - break; - case '\\': - putChar('\\'); - break; - case 'Z': - putChar((char) 0x1A); // ctrl + Z - break; - default: - putChar(ch); - break; - } - - continue; - } - if (ch == '\'') { - scanChar(); - if (ch != '\'') { - token = LITERAL_CHARS; - break; - } else { - if (!hasSpecial) { - initBuff(bufPos); - arraycopy(mark + 1, buf, 0, bufPos); - hasSpecial = true; - } - putChar('\''); - continue; - } - } - - if (!hasSpecial) { - bufPos++; - continue; - } - - if (bufPos == buf.length) { - putChar(ch); - } else { - buf[bufPos++] = ch; - } - } - - if (!hasSpecial) { - stringVal = subString(mark + 1, bufPos); - } else { - stringVal = new String(buf, 0, bufPos); - } + scanString2(); } public void scanComment() { diff --git a/src/main/java/com/alibaba/druid/sql/dialect/odps/parser/OdpsLexer.java b/src/main/java/com/alibaba/druid/sql/dialect/odps/parser/OdpsLexer.java index cc36308187..e3d9b30927 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/odps/parser/OdpsLexer.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/odps/parser/OdpsLexer.java @@ -320,4 +320,8 @@ public class OdpsLexer extends Lexer { super.scanVariable(); } + + protected final void scanString() { + scanString2(); + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/odps/visitor/OdpsOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/odps/visitor/OdpsOutputVisitor.java index 29a1358653..f46b3a636f 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/odps/visitor/OdpsOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/odps/visitor/OdpsOutputVisitor.java @@ -25,6 +25,7 @@ import com.alibaba.druid.sql.ast.SQLOrderBy; import com.alibaba.druid.sql.ast.SQLSetQuantifier; import com.alibaba.druid.sql.ast.SQLStatement; import com.alibaba.druid.sql.ast.expr.SQLCaseExpr; +import com.alibaba.druid.sql.ast.expr.SQLCharExpr; import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr; import com.alibaba.druid.sql.ast.statement.SQLAssignItem; import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; @@ -874,4 +875,18 @@ public class OdpsOutputVisitor extends SQLASTOutputVisitor implements OdpsASTVis decrementIndent(); return false; } + + public boolean visit(SQLCharExpr x) { + String text = x.getText(); + if (text == null) { + print0(ucase ? "NULL" : "null"); + } else { + print('\''); + String text2 = text.replaceAll("\\'", "\\\\'"); + print0(text2); + print('\''); + } + + return false; + } } 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 d53d185da8..7b86ea77f0 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/Lexer.java +++ b/src/main/java/com/alibaba/druid/sql/parser/Lexer.java @@ -15,9 +15,6 @@ */ package com.alibaba.druid.sql.parser; -import com.alibaba.druid.util.StringUtils; -import org.apache.commons.lang.math.NumberUtils; - import static com.alibaba.druid.sql.parser.CharTypes.isFirstIdentifierChar; import static com.alibaba.druid.sql.parser.CharTypes.isIdentifierChar; import static com.alibaba.druid.sql.parser.CharTypes.isWhitespace; @@ -42,6 +39,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import org.apache.commons.lang.math.NumberUtils; + /** * @author wenshao [szujobs@hotmail.com] */ @@ -673,6 +672,131 @@ public class Lexer { stringVal = new String(buf, 0, bufPos); } } + + protected final void scanString2() { + { + boolean hasSpecial = false; + int startIndex = pos + 1; + int endIndex = -1; // text.indexOf('\'', startIndex); + for (int i = startIndex; i < text.length(); ++i) { + final char ch = text.charAt(i); + if (ch == '\\') { + hasSpecial = true; + continue; + } + if (ch == '\'') { + endIndex = i; + break; + } + } + + if (endIndex == -1) { + throw new ParserException("unclosed str"); + } + + String stringVal = subString(startIndex, endIndex - startIndex); + // hasSpecial = stringVal.indexOf('\\') != -1; + + if (!hasSpecial) { + this.stringVal = stringVal; + int pos = endIndex + 1; + char ch = charAt(pos); + if (ch != '\'') { + this.pos = pos; + this.ch = ch; + token = LITERAL_CHARS; + return; + } + } + } + + mark = pos; + boolean hasSpecial = false; + for (;;) { + if (isEOF()) { + lexError("unclosed.str.lit"); + return; + } + + ch = charAt(++pos); + + if (ch == '\\') { + scanChar(); + if (!hasSpecial) { + initBuff(bufPos); + arraycopy(mark + 1, buf, 0, bufPos); + hasSpecial = true; + } + + switch (ch) { + case '0': + putChar('\0'); + break; + case '\'': + putChar('\''); + break; + case '"': + putChar('"'); + break; + case 'b': + putChar('\b'); + break; + case 'n': + putChar('\n'); + break; + case 'r': + putChar('\r'); + break; + case 't': + putChar('\t'); + break; + case '\\': + putChar('\\'); + break; + case 'Z': + putChar((char) 0x1A); // ctrl + Z + break; + default: + putChar(ch); + break; + } + + continue; + } + if (ch == '\'') { + scanChar(); + if (ch != '\'') { + token = LITERAL_CHARS; + break; + } else { + if (!hasSpecial) { + initBuff(bufPos); + arraycopy(mark + 1, buf, 0, bufPos); + hasSpecial = true; + } + putChar('\''); + continue; + } + } + + if (!hasSpecial) { + bufPos++; + continue; + } + + if (bufPos == buf.length) { + putChar(ch); + } else { + buf[bufPos++] = ch; + } + } + + if (!hasSpecial) { + stringVal = subString(mark + 1, bufPos); + } else { + stringVal = new String(buf, 0, bufPos); + } + } private final void scanAlias() { mark = pos; diff --git a/src/test/java/com/alibaba/druid/bvt/sql/odps/OdpsSelectTest11.java b/src/test/java/com/alibaba/druid/bvt/sql/odps/OdpsSelectTest11.java new file mode 100644 index 0000000000..1efcb8ad28 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/odps/OdpsSelectTest11.java @@ -0,0 +1,59 @@ +/* + * Copyright 1999-2101 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.odps; + +import java.util.List; + +import org.junit.Assert; + +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.visitor.SchemaStatVisitor; +import com.alibaba.druid.stat.TableStat.Column; +import com.alibaba.druid.util.JdbcConstants; + +import junit.framework.TestCase; + +public class OdpsSelectTest11 extends TestCase { + + public void test_select() throws Exception { + String sql = "select 'a\\'b' from abc;";// + Assert.assertEquals("SELECT 'a\\'b'" + + "\nFROM abc;", SQLUtils.formatOdps(sql)); + Assert.assertEquals("select 'a\\'b'" + + "\nfrom abc;", SQLUtils.formatOdps(sql, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION)); + + List statementList = SQLUtils.parseStatements(sql, JdbcConstants.ODPS); + SQLStatement stmt = statementList.get(0); + + Assert.assertEquals(1, statementList.size()); + + SchemaStatVisitor visitor = SQLUtils.createSchemaStatVisitor(JdbcConstants.ODPS); + stmt.accept(visitor); + +// System.out.println("Tables : " + visitor.getTables()); +// System.out.println("fields : " + visitor.getColumns()); +// System.out.println("coditions : " + visitor.getConditions()); +// System.out.println("orderBy : " + visitor.getOrderByColumns()); + + Assert.assertEquals(1, visitor.getTables().size()); + Assert.assertEquals(0, visitor.getColumns().size()); + Assert.assertEquals(0, visitor.getConditions().size()); + +// Assert.assertTrue(visitor.getColumns().contains(new Column("abc", "name"))); + } + +}