添加postgresql的begin,commit,set命令解析

添加PGStatement的测试代码,修复PGStatement解析bug;修复pg无法识别table别名问题

将PG的关键字移入TOKEN中

start transaction的visit优化
This commit is contained in:
Terry Zhu
2017-05-17 16:39:44 +08:00
parent ed57e419c4
commit b531cb8c24
19 changed files with 603 additions and 63 deletions
@@ -0,0 +1,43 @@
/*
* Copyright 1999-2017 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.sql.dialect.postgresql.ast.stmt;
import com.alibaba.druid.sql.ast.SQLStatementImpl;
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGASTVisitor;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
import com.alibaba.druid.util.JdbcConstants;
public class PGBeginStatement extends SQLStatementImpl implements PGSQLStatement {
public final boolean isBegin;
public PGBeginStatement(boolean isBegin) {
super(JdbcConstants.POSTGRESQL);
this.isBegin = isBegin;
}
@Override
protected void accept0(SQLASTVisitor visitor) {
if (visitor instanceof PGASTVisitor) {
accept0((PGASTVisitor) visitor);
}
}
@Override
public void accept0(PGASTVisitor visitor) {
visitor.visit(this);
visitor.endVisit(this);
}
}
@@ -0,0 +1,43 @@
/*
* Copyright 1999-2017 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.sql.dialect.postgresql.ast.stmt;
import com.alibaba.druid.sql.ast.SQLStatementImpl;
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGASTVisitor;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
import com.alibaba.druid.util.JdbcConstants;
// 暂时不支持END命令
public class PGCommitStatement extends SQLStatementImpl implements PGSQLStatement {
// COMMIT
public PGCommitStatement() {
super(JdbcConstants.POSTGRESQL);
}
@Override
protected void accept0(SQLASTVisitor visitor) {
if (visitor instanceof PGASTVisitor) {
accept0((PGASTVisitor) visitor);
}
}
@Override
public void accept0(PGASTVisitor visitor) {
visitor.visit(this);
visitor.endVisit(this);
}
}
@@ -28,7 +28,7 @@ import com.alibaba.druid.sql.dialect.postgresql.ast.PGWithClause;
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGASTVisitor;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public class PGSelectQueryBlock extends SQLSelectQueryBlock {
public class PGSelectQueryBlock extends SQLSelectQueryBlock implements PGSQLObject{
private PGWithClause with;
private List<SQLExpr> distinctOn = new ArrayList<SQLExpr>(2);
@@ -56,7 +56,8 @@ public class PGSelectQueryBlock extends SQLSelectQueryBlock {
accept0((PGASTVisitor) visitor);
}
protected void accept0(PGASTVisitor visitor) {
@Override
public void accept0(PGASTVisitor visitor) {
if (visitor.visit(this)) {
acceptChild(visitor, this.with);
acceptChild(visitor, this.distinctOn);
@@ -0,0 +1,52 @@
/*
* Copyright 1999-2017 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.sql.dialect.postgresql.ast.stmt;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.statement.SQLSetStatement;
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGASTVisitor;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
import com.alibaba.druid.util.JdbcConstants;
import java.util.List;
public class PGSetStatement extends SQLSetStatement implements PGSQLStatement {
public final String range;
public final String param;
public final List<SQLExpr> values;
// SET [ SESSION | LOCAL ] TIME ZONE { timezone | LOCAL | DEFAULT }
// SET [ SESSION | LOCAL ] configuration_parameter { TO | = } { value | 'value' | DEFAULT }
public PGSetStatement(String range, String param, List<SQLExpr> values) {
super(JdbcConstants.POSTGRESQL);
this.range = range;
this.param = param;
this.values = values;
}
@Override
protected void accept0(SQLASTVisitor visitor) {
if (visitor instanceof PGASTVisitor) {
accept0((PGASTVisitor) visitor);
}
}
@Override
public void accept0(PGASTVisitor visitor) {
visitor.visit(this);
visitor.endVisit(this);
}
}
@@ -237,4 +237,24 @@ public class PGExprParser extends SQLExprParser {
return super.primaryRest(expr);
}
@Override
protected String alias() {
String alias = super.alias();
if (alias != null) {
return alias;
}
// 某些关键字在alias时,不作为关键字,仍然是作用为别名
switch (lexer.token()) {
case INTERSECT:
// 具体可以参考SQLParser::alias()的方法实现
alias = lexer.stringVal();
lexer.nextToken();
return alias;
// TODO other cases
default:
break;
}
return alias;
}
}
@@ -34,6 +34,7 @@ public class PGLexer extends Lexer {
map.putAll(Keywords.DEFAULT_KEYWORDS.getKeywords());
map.put("BEGIN", Token.BEGIN);
map.put("CASCADE", Token.CASCADE);
map.put("CONTINUE", Token.CONTINUE);
map.put("CURRENT", Token.CURRENT);
@@ -57,7 +58,8 @@ public class PGLexer extends Lexer {
map.put("ROWS", Token.ROWS);
map.put("SHARE", Token.SHARE);
map.put("SHOW", Token.SHOW);
map.put("START", Token.START);
map.put("USING", Token.USING);
map.put("WINDOW", Token.WINDOW);
@@ -15,20 +15,14 @@
*/
package com.alibaba.druid.sql.dialect.postgresql.parser;
import java.util.List;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
import com.alibaba.druid.sql.ast.expr.SQLCurrentOfCursorExpr;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLQueryExpr;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableAlterColumn;
import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
import com.alibaba.druid.sql.ast.statement.SQLInsertStatement;
import com.alibaba.druid.sql.ast.statement.SQLSelect;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement;
import com.alibaba.druid.sql.ast.statement.*;
import com.alibaba.druid.sql.dialect.postgresql.ast.PGWithClause;
import com.alibaba.druid.sql.dialect.postgresql.ast.PGWithQuery;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGDeleteStatement;
@@ -37,9 +31,26 @@ import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGShowStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGUpdateStatement;
import com.alibaba.druid.sql.parser.*;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.*;
import com.alibaba.druid.sql.parser.Lexer;
import com.alibaba.druid.sql.parser.ParserException;
import com.alibaba.druid.sql.parser.SQLStatementParser;
import com.alibaba.druid.sql.parser.Token;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class PGSQLStatementParser extends SQLStatementParser {
public static final String TIME_ZONE = "TIME ZONE";
public static final String TIME = "TIME";
public static final String LOCAL = "LOCAL";
public static final String TRANSACTION = "TRANSACTION";
public PGSQLStatementParser(PGExprParser parser) {
super(parser);
}
public PGSQLStatementParser(String sql){
super(new PGExprParser(sql));
}
@@ -210,15 +221,36 @@ public class PGSQLStatementParser extends SQLStatementParser {
}
public boolean parseStatementListDialect(List<SQLStatement> statementList) {
if (lexer.token() == Token.WITH) {
SQLStatement stmt = parseWith();
statementList.add(stmt);
switch (lexer.token()) {
case BEGIN:
statementList.add(handleBegin());
return true;
case START:
return handleStart(statementList);
case WITH:
statementList.add(parseWith());
return true;
default:
return false;
}
return false;
}
private SQLStatement handleBegin() {
SQLStatement statement = new PGBeginStatement(true);
lexer.nextToken();
return statement;
}
private boolean handleStart(List<SQLStatement> statementList) {
lexer.nextToken();
if (lexer.token() == Token.IDENTIFIER && TRANSACTION.equalsIgnoreCase(lexer.stringVal())) {
statementList.add(new PGBeginStatement(false));
lexer.nextToken();
return true;
}
return false;
}
public PGWithClause parseWithClause() {
lexer.nextToken();
@@ -371,7 +403,76 @@ public class PGSQLStatementParser extends SQLStatementParser {
public SQLStatement parseShow() {
accept(Token.SHOW);
PGShowStatement stmt = new PGShowStatement();
stmt.setExpr(this.exprParser.expr());
switch (lexer.token()) {
case ALL:
stmt.setExpr(new SQLIdentifierExpr(Token.ALL.name()));
lexer.nextToken();
break;
default:
stmt.setExpr(this.exprParser.expr());
break;
}
return stmt;
}
@Override
public SQLStatement parseCommit() {
SQLStatement statment = new PGCommitStatement();
lexer.nextToken();
return statment;
}
private SQLStatement handleTimeZoneSet(String range) {
// ZONE
lexer.nextToken();
// VALUE
lexer.nextToken();
String value = lexer.stringVal();
List<SQLExpr> exprs = new ArrayList<SQLExpr>();
if (lexer.token() == Token.IDENTIFIER) {
exprs.add(new SQLIdentifierExpr(value.toUpperCase()));
} else {
exprs.add(new SQLCharExpr(value));
}
lexer.nextToken();
return new PGSetStatement(range, TIME_ZONE, exprs);
}
@Override
public SQLStatement parseSet() {
accept(Token.SET);
Token token = lexer.token();
String range = "";
if (token == Token.SESSION) {
lexer.nextToken();
range = Token.SESSION.name();
} else if (token == Token.IDENTIFIER && LOCAL.equalsIgnoreCase(lexer.stringVal())) {
range = LOCAL;
lexer.nextToken();
}
String parameter = lexer.stringVal();
if (TIME.equalsIgnoreCase(parameter)) {
// SET [ SESSION | LOCAL ] TIME ZONE { timezone | LOCAL | DEFAULT }
return handleTimeZoneSet(range);
}
// TO | =
lexer.nextToken();
// value | 'value' | DEFAULT
List<SQLExpr> values = new ArrayList<SQLExpr>();
while (!lexer.isEOF()) {
lexer.nextToken();
if (lexer.token() == Token.LITERAL_CHARS) {
values.add(new SQLCharExpr(lexer.stringVal()));
} else if (lexer.token() == Token.LITERAL_INT) {
values.add(new SQLIdentifierExpr(lexer.numberString()));
} else {
values.add(new SQLIdentifierExpr(lexer.stringVal()));
}
// skip comma
lexer.nextToken();
}
return new PGSetStatement(range, parameter, values);
}
}
@@ -281,6 +281,10 @@ public class PGSelectParser extends SQLSelectParser {
return super.parseTableSourceRest(functionTableSource);
}
if (alias != null) {
tableSource.setAlias(alias);
return super.parseTableSourceRest(tableSource);
}
}
return super.parseTableSourceRest(tableSource);
@@ -17,25 +17,8 @@ package com.alibaba.druid.sql.dialect.postgresql.visitor;
import com.alibaba.druid.sql.dialect.postgresql.ast.PGWithClause;
import com.alibaba.druid.sql.dialect.postgresql.ast.PGWithQuery;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGBoxExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGCidrExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGCircleExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGExtractExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGInetExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGIntervalExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGLineSegmentsExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGMacAddrExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGPointExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGPolygonExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGTypeCastExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGDeleteStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGFunctionTableSource;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGInsertStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGShowStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGUpdateStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGValuesQuery;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.*;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.*;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public interface PGASTVisitor extends SQLASTVisitor {
@@ -136,4 +119,16 @@ public interface PGASTVisitor extends SQLASTVisitor {
boolean visit(PGShowStatement x);
void endVisit(PGBeginStatement x);
boolean visit(PGBeginStatement x);
void endVisit(PGCommitStatement x);
boolean visit(PGCommitStatement x);
void endVisit(PGSetStatement x);
boolean visit(PGSetStatement x);
}
@@ -28,17 +28,10 @@ import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGMacAddrExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGPointExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGPolygonExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGTypeCastExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGDeleteStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGFunctionTableSource;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGInsertStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.*;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock.FetchClause;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock.ForClause;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock.WindowClause;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGShowStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGUpdateStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGValuesQuery;
import com.alibaba.druid.sql.visitor.SQLASTVisitorAdapter;
public class PGASTVisitorAdapter extends SQLASTVisitorAdapter implements PGASTVisitor {
@@ -288,4 +281,34 @@ public class PGASTVisitorAdapter extends SQLASTVisitorAdapter implements PGASTVi
return true;
}
@Override
public void endVisit(PGBeginStatement x) {
}
@Override
public boolean visit(PGBeginStatement x) {
return true;
}
@Override
public void endVisit(PGCommitStatement x) {
}
@Override
public boolean visit(PGCommitStatement x) {
return true;
}
@Override
public void endVisit(PGSetStatement x) {
}
@Override
public boolean visit(PGSetStatement x) {
return true;
}
}
@@ -33,18 +33,14 @@ import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGMacAddrExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGPointExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGPolygonExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGTypeCastExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGDeleteStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGFunctionTableSource;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGInsertStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.*;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock.FetchClause;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock.ForClause;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock.WindowClause;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGShowStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGUpdateStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGValuesQuery;
import com.alibaba.druid.sql.dialect.postgresql.parser.PGSQLStatementParser;
import com.alibaba.druid.sql.parser.Token;
import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor;
import com.alibaba.druid.util.StringUtils;
public class PGOutputVisitor extends SQLASTOutputVisitor implements PGASTVisitor {
@@ -637,7 +633,59 @@ public class PGOutputVisitor extends SQLASTOutputVisitor implements PGASTVisitor
print0(ucase ? " OFFSET " : " offset ");
x.getOffset().accept(this);
}
return false;
}
@Override
public void endVisit(PGBeginStatement x) {
}
@Override
public boolean visit(PGBeginStatement x) {
print0(x.isBegin ? "BEGIN" : "START TRANSACTION");
return false;
}
@Override
public void endVisit(PGCommitStatement x) {
}
@Override
public boolean visit(PGCommitStatement x) {
print0(ucase ? "COMMIT" : "commit");
return false;
}
@Override
public void endVisit(PGSetStatement x) {
}
@Override
public boolean visit(PGSetStatement x) {
print0(ucase ? "SET " : "set ");
if (!StringUtils.isEmpty(x.range)) {
print0(x.range);
print0(" ");
}
if (PGSQLStatementParser.TIME_ZONE.equalsIgnoreCase(x.param)) {
print0(PGSQLStatementParser.TIME_ZONE);
print0(" ");
x.values.get(0).accept(this);
return false;
}
print0(x.param);
print0(" ");
print0(Token.TO.name());
print0(" ");
for (int i = 0; i < x.values.size(); i++) {
if (i != 0) {
print0(", ");
}
x.values.get(i).accept(this);
}
return false;
}
}
@@ -34,17 +34,10 @@ import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGMacAddrExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGPointExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGPolygonExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.expr.PGTypeCastExpr;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGDeleteStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGFunctionTableSource;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGInsertStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.*;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock.FetchClause;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock.ForClause;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock.WindowClause;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGShowStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGUpdateStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGValuesQuery;
import com.alibaba.druid.sql.visitor.SchemaStatVisitor;
import com.alibaba.druid.stat.TableStat;
import com.alibaba.druid.stat.TableStat.Mode;
@@ -401,4 +394,34 @@ public class PGSchemaStatVisitor extends SchemaStatVisitor implements PGASTVisit
public boolean visit(PGShowStatement x) {
return false;
}
@Override
public void endVisit(PGBeginStatement x) {
}
@Override
public boolean visit(PGBeginStatement x) {
return false;
}
@Override
public void endVisit(PGCommitStatement x) {
}
@Override
public boolean visit(PGCommitStatement x) {
return false;
}
@Override
public void endVisit(PGSetStatement x) {
}
@Override
public boolean visit(PGSetStatement x) {
return false;
}
}