diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/stmt/PGBeginStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/stmt/PGBeginStatement.java new file mode 100644 index 0000000000..8f9091651e --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/stmt/PGBeginStatement.java @@ -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); + } +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/stmt/PGCommitStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/stmt/PGCommitStatement.java new file mode 100644 index 0000000000..4fcd300fb1 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/stmt/PGCommitStatement.java @@ -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); + } +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/stmt/PGSelectQueryBlock.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/stmt/PGSelectQueryBlock.java index 29261a3617..89498958f6 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/stmt/PGSelectQueryBlock.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/stmt/PGSelectQueryBlock.java @@ -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 distinctOn = new ArrayList(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); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/stmt/PGSetStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/stmt/PGSetStatement.java new file mode 100644 index 0000000000..4a6cdf59a1 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/stmt/PGSetStatement.java @@ -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 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 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); + } +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGExprParser.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGExprParser.java index 05c0a75edf..f594722b38 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGExprParser.java @@ -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; + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGLexer.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGLexer.java index 2c6a459a0b..9007059d10 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGLexer.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGLexer.java @@ -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); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGSQLStatementParser.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGSQLStatementParser.java index 87c0789055..6b0bdb7441 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGSQLStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGSQLStatementParser.java @@ -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 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 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 exprs = new ArrayList(); + 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 values = new ArrayList(); + 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); + } + } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGSelectParser.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGSelectParser.java index 258548a271..018a0ea7ea 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGSelectParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGSelectParser.java @@ -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); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGASTVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGASTVisitor.java index 21f603f5f7..edb6836172 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGASTVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGASTVisitor.java @@ -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); + } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGASTVisitorAdapter.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGASTVisitorAdapter.java index a96b539ef2..8cba7ad432 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGASTVisitorAdapter.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGASTVisitorAdapter.java @@ -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; + } + } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java index 555255edeb..ed15b5214c 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java @@ -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; } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGSchemaStatVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGSchemaStatVisitor.java index 2257106352..449954ae7f 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGSchemaStatVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGSchemaStatVisitor.java @@ -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; + } } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGBeginTest.java b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGBeginTest.java new file mode 100644 index 0000000000..8d682252c2 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGBeginTest.java @@ -0,0 +1,32 @@ +/* + * 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.bvt.sql.postgresql; + +import com.alibaba.druid.sql.PGTest; +import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGBeginStatement; + +public class PGBeginTest extends PGTest { + public void testBegin() throws Exception { + String sql = "begin;"; + String expected = "BEGIN"; + testParseSql(sql, expected, expected, PGBeginStatement.class); + + sql = "start transaction;"; + expected = "START TRANSACTION"; + testParseSql(sql, expected, expected, PGBeginStatement.class); + } + +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGCommitTest.java b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGCommitTest.java new file mode 100644 index 0000000000..30b773856d --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGCommitTest.java @@ -0,0 +1,27 @@ +/* + * 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.bvt.sql.postgresql; + +import com.alibaba.druid.sql.PGTest; +import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGCommitStatement; + +public class PGCommitTest extends PGTest { + public void testCommit() throws Exception { + String sql = "commit;"; + String expected = "COMMIT"; + testParseSql(sql, expected, expected, PGCommitStatement.class); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGFromAsTest.java b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGFromAsTest.java new file mode 100644 index 0000000000..6cba77fbc5 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGFromAsTest.java @@ -0,0 +1,29 @@ +/* + * 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.bvt.sql.postgresql; + +import com.alibaba.druid.sql.PGTest; +import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectStatement; + +public class PGFromAsTest extends PGTest { + public void testFromAs() throws Exception { + String sql = "SELECT Count(*) FROM tb_abc AS t1 WHERE ((t1.a_id = 'global_a_id') AND (t1.owner = 'global_bc'));"; + String expectedSql = "SELECT COUNT(*)\nFROM tb_abc t1\nWHERE t1.a_id = 'global_a_id'\n\tAND t1.owner = 'global_bc'"; + String expectedPattern = "SELECT COUNT(*)\nFROM tb_abc t1\nWHERE t1.a_id = ?\n\tAND t1.owner = ?"; + testParseSql(sql, expectedSql, expectedPattern, PGSelectStatement.class); + } + +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSetTest3.java b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSetTest3.java new file mode 100644 index 0000000000..94f01fd804 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSetTest3.java @@ -0,0 +1,50 @@ +/* + * 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.bvt.sql.postgresql; + +import com.alibaba.druid.sql.PGTest; +import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSetStatement; + +public class PGSetTest3 extends PGTest { + public void testSet() throws Exception { + Class type = PGSetStatement.class; + + String sql = "SET TIME ZONE 'Europe/Rome';"; + String expectedSql = "SET TIME ZONE 'Europe/Rome'"; + String expectedPattern = "SET TIME ZONE ?"; + testParseSql(sql, expectedSql, expectedPattern, type); + + sql = "SET configuration_parameter TO DEFAULT;"; + expectedSql = "SET configuration_parameter TO DEFAULT"; + testParseSql(sql, expectedSql, expectedSql, type); + + sql = "SET search_path TO my_schema, public;"; + expectedSql = "SET search_path TO my_schema, public"; + testParseSql(sql, expectedSql, expectedSql, type); + + sql = "SET search_path = my_schema, public;"; + expectedSql = "SET search_path TO my_schema, public"; + testParseSql(sql, expectedSql, expectedSql, type); + + sql = "SET a=1"; + expectedSql = "SET a TO 1"; + testParseSql(sql, expectedSql, expectedSql, type); + + sql = "SET a=1,2"; + expectedSql = "SET a TO 1, 2"; + testParseSql(sql, expectedSql, expectedSql, type); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGShowTest1.java b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGShowTest1.java new file mode 100644 index 0000000000..1f312dadf7 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGShowTest1.java @@ -0,0 +1,31 @@ +/* + * 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.bvt.sql.postgresql; + +import com.alibaba.druid.sql.PGTest; +import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGShowStatement; + +public class PGShowTest1 extends PGTest { + public void testShowAll() throws Exception { + String sql = "show all;"; + String expected = "SHOW ALL"; + testParseSql(sql, expected, expected, PGShowStatement.class); + + sql = "show transaction_read_only;"; + expected = "SHOW transaction_read_only"; + testParseSql(sql, expected, expected, PGShowStatement.class); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/postgresql/select/PGSelectTest42.java b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/select/PGSelectTest42.java index b3c9e119c5..42bd81a97f 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/postgresql/select/PGSelectTest42.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/select/PGSelectTest42.java @@ -33,13 +33,13 @@ public class PGSelectTest42 extends PGTest { List statementList = parser.parseStatementList(); SQLStatement stmt = statementList.get(0); - Assert.assertEquals("UPDATE sys_account\n" + + Assert.assertEquals("UPDATE sys_account a\n" + "SET online = 2\n" + "FROM auto_handler_online o\n" + "WHERE a.id = o.account_id\n" + "\tAND a.online != 2", SQLUtils.toPGString(stmt)); - Assert.assertEquals("update sys_account\n" + + Assert.assertEquals("update sys_account a\n" + "set online = 2\n" + "from auto_handler_online o\n" + "where a.id = o.account_id\n" + diff --git a/src/test/java/com/alibaba/druid/sql/PGTest.java b/src/test/java/com/alibaba/druid/sql/PGTest.java index fbd938c959..73c3b138d8 100644 --- a/src/test/java/com/alibaba/druid/sql/PGTest.java +++ b/src/test/java/com/alibaba/druid/sql/PGTest.java @@ -17,10 +17,12 @@ package com.alibaba.druid.sql; import java.util.List; +import com.alibaba.druid.sql.dialect.postgresql.parser.PGSQLStatementParser; import junit.framework.TestCase; import com.alibaba.druid.sql.ast.SQLStatement; import com.alibaba.druid.sql.dialect.postgresql.visitor.PGOutputVisitor; +import org.junit.Assert; public class PGTest extends TestCase { protected String output(List stmtList) { @@ -42,4 +44,18 @@ public class PGTest extends TestCase { } System.out.println(text); } + + protected void testParseSql(String sql, String expectedSql, String expectedPattern, Class type) { + PGSQLStatementParser parser = new PGSQLStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement statement = statementList.get(0); + + Assert.assertEquals(1, statementList.size()); + Assert.assertTrue(type.isAssignableFrom(statement.getClass())); + + StringBuilder sb = new StringBuilder(); + PGOutputVisitor visitor = new PGOutputVisitor(sb); + statement.accept(visitor); + Assert.assertEquals(expectedSql, sb.toString()); + } }