From 042259bb68ed9b4b374a7d53c4e77b596c6ab9ef Mon Sep 17 00:00:00 2001 From: shenfeng Date: Wed, 8 Jun 2022 19:42:26 +0800 Subject: [PATCH] fix #4812 --- .../mysql/parser/MySqlStatementParser.java | 43 ++++++++----------- .../com/alibaba/druid/sql/parser/Lexer.java | 17 +++++++- .../druid/sql/parser/SQLSelectListCache.java | 1 + .../druid/sql/parser/SQLStatementParser.java | 5 +-- .../druid/sql/parser/SQLLexerTest2.java | 24 +++++++++++ 5 files changed, 60 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java index d582561d73..a85f871928 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java @@ -1752,8 +1752,7 @@ public class MySqlStatementParser extends SQLStatementParser { if (lexer.token() == Token.IDENTIFIER) { String label = lexer.stringVal(); - char ch = lexer.current(); - int bp = lexer.bp(); + Lexer.SavePoint savePoint = lexer.markOut(); lexer.nextToken(); if (lexer.token() == Token.VARIANT && lexer.stringVal().equals(":")) { lexer.nextToken(); @@ -1773,7 +1772,7 @@ public class MySqlStatementParser extends SQLStatementParser { } return true; } else { - lexer.reset(bp, ch, Token.IDENTIFIER); + lexer.reset(savePoint); } } @@ -7909,26 +7908,24 @@ public class MySqlStatementParser extends SQLStatementParser { if (dbType != DbType.mysql) { while (lexer.token() == Token.COMMA) { - char markChar = lexer.current(); - int markBp = lexer.bp(); - + Lexer.SavePoint savePoint = lexer.markOut(); lexer.nextToken(); if (lexer.identifierEquals(FnvHash.Constants.CHANGE) || lexer.identifierEquals(FnvHash.Constants.MODIFY)) { - lexer.reset(markBp, markChar, Token.COMMA); + lexer.reset(savePoint); break; } if (lexer.token() == Token.IDENTIFIER) { if ("ADD".equalsIgnoreCase(lexer.stringVal())) { - lexer.reset(markBp, markChar, Token.COMMA); + lexer.reset(savePoint); break; } name = exprParser.name(); name.setParent(item); item.addColumn(name); } else { - lexer.reset(markBp, markChar, Token.COMMA); + lexer.reset(savePoint); break; } } @@ -8718,12 +8715,11 @@ public class MySqlStatementParser extends SQLStatementParser { // select if (lexer.token() == Token.LPAREN) { - char ch = lexer.current(); - int bp = lexer.bp(); + Lexer.SavePoint savePoint = lexer.markOut(); lexer.nextToken(); if (lexer.token() == Token.SELECT) { - lexer.reset(bp, ch, Token.LPAREN); + lexer.reset(savePoint); statementList.add(this.parseSelect()); continue; } else { @@ -8811,8 +8807,7 @@ public class MySqlStatementParser extends SQLStatementParser { if (lexer.token() == Token.IDENTIFIER) { String label = lexer.stringVal(); - char ch = lexer.current(); - int bp = lexer.bp(); + Lexer.SavePoint savePoint = lexer.markOut(); lexer.nextToken(); if (lexer.token() == Token.VARIANT && lexer.stringVal().equals(":")) { lexer.nextToken(); @@ -8831,7 +8826,7 @@ public class MySqlStatementParser extends SQLStatementParser { } continue; } else { - lexer.reset(bp, ch, Token.IDENTIFIER); + lexer.reset(savePoint); } } @@ -9040,30 +9035,29 @@ public class MySqlStatementParser extends SQLStatementParser { * parse declare statement */ public SQLStatement parseDeclare() { - char markChar = lexer.current(); - int markBp = lexer.bp(); + Lexer.SavePoint savePoint = lexer.markOut(); lexer.nextToken(); if (lexer.token() == Token.CONTINUE) { - lexer.reset(markBp, markChar, Token.DECLARE); + lexer.reset(savePoint); return this.parseDeclareHandler(); } lexer.nextToken(); if (lexer.token() == Token.CURSOR) { - lexer.reset(markBp, markChar, Token.DECLARE); + lexer.reset(savePoint); return this.parseCursorDeclare(); } else if (lexer.identifierEquals("HANDLER")) { //DECLARE异常处理程序 [add by zhujun 2016-04-16] - lexer.reset(markBp, markChar, Token.DECLARE); + lexer.reset(savePoint); return this.parseDeclareHandler(); } else if (lexer.token() == Token.CONDITION) { //DECLARE异常 [add by zhujun 2016-04-17] - lexer.reset(markBp, markChar, Token.DECLARE); + lexer.reset(savePoint); return this.parseDeclareCondition(); } else { - lexer.reset(markBp, markChar, Token.DECLARE); + lexer.reset(savePoint); } MySqlDeclareStatement stmt = new MySqlDeclareStatement(); @@ -9274,12 +9268,11 @@ public class MySqlStatementParser extends SQLStatementParser { // select if (lexer.token() == Token.LPAREN) { - char ch = lexer.current(); - int bp = lexer.bp(); + Lexer.SavePoint savePoint = lexer.markOut(); lexer.nextToken(); if (lexer.token() == Token.SELECT) { - lexer.reset(bp, ch, Token.LPAREN); + lexer.reset(savePoint); return this.parseSelect(); } else { throw new ParserException("TODO. " + lexer.info()); 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 17ede2f1bd..ff6e016d39 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/Lexer.java +++ b/src/main/java/com/alibaba/druid/sql/parser/Lexer.java @@ -178,6 +178,7 @@ public class Lexer { public static class SavePoint { int bp; + int startPos; int sp; int np; char ch; @@ -191,7 +192,13 @@ public class Lexer { return keywords; } + //出现多次调用mark()后调用reset()会有问题 + @Deprecated public SavePoint mark() { + return this.savePoint = markOut(); + } + + public SavePoint markOut() { SavePoint savePoint = new SavePoint(); savePoint.bp = pos; savePoint.sp = bufPos; @@ -201,9 +208,11 @@ public class Lexer { savePoint.stringVal = stringVal; savePoint.hash = hash; savePoint.hash_lower = hash_lower; - return this.savePoint = savePoint; + savePoint.startPos = startPos; + return savePoint; } + public void reset(SavePoint savePoint) { this.pos = savePoint.bp; this.bufPos = savePoint.sp; @@ -213,8 +222,10 @@ public class Lexer { this.stringVal = savePoint.stringVal; this.hash = savePoint.hash; this.hash_lower = savePoint.hash_lower; + this.startPos = savePoint.startPos; } - + //出现多次调用mark()后调用reset()会有问题 + @Deprecated public void reset() { this.reset(this.savePoint); } @@ -3123,6 +3134,8 @@ public class Lexer { return this.ch; } + //todo fix reset reset字段会导致lexer的游标不对齐 不建议使用 + @Deprecated public void reset(int mark, char markChar, Token token) { this.pos = mark; this.ch = markChar; diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLSelectListCache.java b/src/main/java/com/alibaba/druid/sql/parser/SQLSelectListCache.java index 2950f6dcfa..1ccbc03f88 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLSelectListCache.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLSelectListCache.java @@ -87,6 +87,7 @@ public class SQLSelectListCache { queryBlock.setCachedSelectList(entry.printSql, entry.printSqlHash); int len = pos + block.length(); + //todo fix reset lexer.reset(len, text.charAt(len), Token.FROM); return true; } diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java b/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java index 85ef0b5bc5..bb2af8c18a 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java @@ -570,8 +570,7 @@ public class SQLStatementParser extends SQLParser { } if (lexer.token == Token.LPAREN) { - char markChar = lexer.current(); - int markBp = lexer.bp(); + Lexer.SavePoint savePoint = lexer.markOut(); int parenCount = 0; do { @@ -585,7 +584,7 @@ public class SQLStatementParser extends SQLParser { } if (lexer.token == Token.SELECT) { - lexer.reset(markBp, markChar, Token.LPAREN); + lexer.reset(savePoint); SQLStatement stmt = parseSelect(); statementList.add(stmt); continue; diff --git a/src/test/java/com/alibaba/druid/sql/parser/SQLLexerTest2.java b/src/test/java/com/alibaba/druid/sql/parser/SQLLexerTest2.java index b4c4d16d85..f3168dd013 100644 --- a/src/test/java/com/alibaba/druid/sql/parser/SQLLexerTest2.java +++ b/src/test/java/com/alibaba/druid/sql/parser/SQLLexerTest2.java @@ -15,7 +15,12 @@ */ package com.alibaba.druid.sql.parser; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser; import junit.framework.TestCase; +import org.junit.Assert; + +import java.util.List; public class SQLLexerTest2 extends TestCase { @@ -67,5 +72,24 @@ public class SQLLexerTest2 extends TestCase { } } } + + public void test_lexer_error_info(){ + String line1 ="SELECT *"; + String line2 ="FORM a"; + String sql = line1 + "\n"+line2; + MySqlStatementParser parser=new MySqlStatementParser(sql); + Exception exception = null; + try { + parser.parseStatementList(); + } catch (Exception e) { + exception = e; + } + assert exception != null; + Assert.assertEquals("not supported.pos 13, line 2, column 2, token IDENTIFIER FORM", exception.getMessage()); + + + + } + }