From 62e0835c607dda1100fc39064d40aadebb189029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A9=E5=B0=91?= Date: Wed, 22 Feb 2012 22:27:10 +0800 Subject: [PATCH] bug fixed for schema stat --- .../sql/ast/statement/SQLDeleteStatement.java | 4 +- .../postgresql/ast/PGCurrentOfExpr.java | 27 + .../postgresql/ast/PGDeleteStatement.java | 67 +++ .../postgresql/ast/PGSelectQueryBlock.java | 76 +-- .../postgresql/ast/PGTruncateStatement.java | 1 + .../dialect/postgresql/ast/PGWithClause.java | 36 ++ .../dialect/postgresql/ast/PGWithQuery.java | 45 ++ .../dialect/postgresql/parser/PGLexer.java | 1 + .../parser/PGSQLStatementParser.java | 104 ++-- .../postgresql/parser/PGSelectParser.java | 11 +- .../postgresql/visitor/PGASTVisitor.java | 20 +- .../visitor/PGASTVisitorAdapter.java | 35 +- .../postgresql/visitor/PGOutputVisitor.java | 473 ++++++++++-------- .../visitor/PGSchemaStatVisitor.java | 81 ++- .../com/alibaba/druid/sql/parser/Token.java | 1 + .../druid/sql/visitor/SchemaStatVisitor.java | 2 - .../bvt/sql/postgresql/PGDeleteTest.java | 39 ++ .../bvt/sql/postgresql/PGDeleteTest2.java | 37 ++ 18 files changed, 725 insertions(+), 335 deletions(-) create mode 100644 src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGCurrentOfExpr.java create mode 100644 src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGDeleteStatement.java create mode 100644 src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGWithClause.java create mode 100644 src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGWithQuery.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGDeleteTest.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGDeleteTest2.java diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLDeleteStatement.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLDeleteStatement.java index 175c902e59..b899e0fd44 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLDeleteStatement.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLDeleteStatement.java @@ -23,8 +23,8 @@ import com.alibaba.druid.sql.visitor.SQLASTVisitor; public class SQLDeleteStatement extends SQLStatementImpl { private static final long serialVersionUID = 1L; - private SQLName tableName; - private SQLExpr where; + protected SQLName tableName; + protected SQLExpr where; public SQLDeleteStatement(){ diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGCurrentOfExpr.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGCurrentOfExpr.java new file mode 100644 index 0000000000..b8a2dd16ac --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGCurrentOfExpr.java @@ -0,0 +1,27 @@ +package com.alibaba.druid.sql.dialect.postgresql.ast; + +import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.dialect.postgresql.visitor.PGASTVisitor; + +public class PGCurrentOfExpr extends PGSQLObjectImpl implements SQLExpr { + + private static final long serialVersionUID = 1L; + private SQLExpr cursor; + + public SQLExpr getCursor() { + return cursor; + } + + public void setCursor(SQLExpr cursor) { + this.cursor = cursor; + } + + @Override + public void accept0(PGASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, cursor); + } + visitor.endVisit(this); + } + +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGDeleteStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGDeleteStatement.java new file mode 100644 index 0000000000..451d7512f3 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGDeleteStatement.java @@ -0,0 +1,67 @@ +package com.alibaba.druid.sql.dialect.postgresql.ast; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.druid.sql.ast.SQLName; +import com.alibaba.druid.sql.ast.statement.SQLDeleteStatement; +import com.alibaba.druid.sql.dialect.postgresql.visitor.PGASTVisitor; +import com.alibaba.druid.sql.visitor.SQLASTVisitor; + +public class PGDeleteStatement extends SQLDeleteStatement implements PGSQLStatement { + + private static final long serialVersionUID = 1L; + private PGWithClause with; + private boolean only = false; + private List using = new ArrayList(2); + private String alias; + + public String getAlias() { + return alias; + } + + public void setAlias(String alias) { + this.alias = alias; + } + + public List getUsing() { + return using; + } + + public void setUsing(List using) { + this.using = using; + } + + public boolean isOnly() { + return only; + } + + public void setOnly(boolean only) { + this.only = only; + } + + public PGWithClause getWith() { + return with; + } + + public void setWith(PGWithClause with) { + this.with = with; + } + + protected void accept0(SQLASTVisitor visitor) { + accept0((PGASTVisitor) visitor); + } + + @Override + public void accept0(PGASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, with); + acceptChild(visitor, tableName); + acceptChild(visitor, using); + acceptChild(visitor, where); + } + + visitor.endVisit(this); + } + +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGSelectQueryBlock.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGSelectQueryBlock.java index 9197cb47a0..05fc7d48e8 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGSelectQueryBlock.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGSelectQueryBlock.java @@ -5,7 +5,6 @@ import java.util.List; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLOrderBy; -import com.alibaba.druid.sql.ast.statement.SQLSelectQuery; import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; import com.alibaba.druid.sql.dialect.postgresql.visitor.PGASTVisitor; import com.alibaba.druid.sql.visitor.SQLASTVisitor; @@ -14,7 +13,7 @@ public class PGSelectQueryBlock extends SQLSelectQueryBlock { private static final long serialVersionUID = 1L; - private WithClause with; + private PGWithClause with; private List distinctOn = new ArrayList(2); private SQLExpr limit; private SQLExpr offset; @@ -81,11 +80,11 @@ public class PGSelectQueryBlock extends SQLSelectQueryBlock { this.window = window; } - public WithClause getWith() { + public PGWithClause getWith() { return with; } - public void setWith(WithClause with) { + public void setWith(PGWithClause with) { this.with = with; } @@ -148,6 +147,7 @@ public class PGSelectQueryBlock extends SQLSelectQueryBlock { acceptChild(visitor, name); acceptChild(visitor, definition); } + visitor.endVisit(this); } } @@ -182,6 +182,7 @@ public class PGSelectQueryBlock extends SQLSelectQueryBlock { if (visitor.visit(this)) { acceptChild(visitor, count); } + visitor.endVisit(this); } } @@ -226,71 +227,7 @@ public class PGSelectQueryBlock extends SQLSelectQueryBlock { if (visitor.visit(this)) { acceptChild(visitor, of); } - } - } - - public static class WithClause extends PGSQLObjectImpl { - private static final long serialVersionUID = 1L; - private boolean recursive = false; - private List withQuery = new ArrayList(2); - - public boolean isRecursive() { - return recursive; - } - - public void setRecursive(boolean recursive) { - this.recursive = recursive; - } - - public List getWithQuery() { - return withQuery; - } - - public void setWithQuery(List withQuery) { - this.withQuery = withQuery; - } - - @Override - public void accept0(PGASTVisitor visitor) { - if (visitor.visit(this)) { - acceptChild(visitor, withQuery); - } - } - } - - public static class WithQuery extends PGSQLObjectImpl { - private static final long serialVersionUID = 1L; - private SQLExpr name; - private final List columns = new ArrayList(); - private SQLSelectQuery subQuery; - - public SQLExpr getName() { - return name; - } - - public void setName(SQLExpr name) { - this.name = name; - } - - public SQLSelectQuery getSubQuery() { - return subQuery; - } - - public void setSubQuery(SQLSelectQuery subQuery) { - this.subQuery = subQuery; - } - - public List getColumns() { - return columns; - } - - @Override - public void accept0(PGASTVisitor visitor) { - if (visitor.visit(this)) { - acceptChild(visitor, name); - acceptChild(visitor, columns); - acceptChild(visitor, subQuery); - } + visitor.endVisit(this); } } @@ -325,6 +262,7 @@ public class PGSelectQueryBlock extends SQLSelectQueryBlock { if (visitor.visit(this)) { acceptChild(visitor, table); } + visitor.endVisit(this); } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGTruncateStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGTruncateStatement.java index 97be5503db..a5936963f4 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGTruncateStatement.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGTruncateStatement.java @@ -39,5 +39,6 @@ public class PGTruncateStatement extends SQLTruncateStatement implements PGSQLSt if (visitor.visit(this)) { acceptChild(visitor, tableNames); } + visitor.endVisit(this); } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGWithClause.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGWithClause.java new file mode 100644 index 0000000000..097b86be9f --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGWithClause.java @@ -0,0 +1,36 @@ +package com.alibaba.druid.sql.dialect.postgresql.ast; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.druid.sql.dialect.postgresql.visitor.PGASTVisitor; + +public class PGWithClause extends PGSQLObjectImpl { + private static final long serialVersionUID = 1L; + private boolean recursive = false; + private List withQuery = new ArrayList(2); + + public boolean isRecursive() { + return recursive; + } + + public void setRecursive(boolean recursive) { + this.recursive = recursive; + } + + public List getWithQuery() { + return withQuery; + } + + public void setWithQuery(List withQuery) { + this.withQuery = withQuery; + } + + @Override + public void accept0(PGASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, withQuery); + } + visitor.endVisit(this); + } +} \ No newline at end of file diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGWithQuery.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGWithQuery.java new file mode 100644 index 0000000000..79b8c57745 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/ast/PGWithQuery.java @@ -0,0 +1,45 @@ +package com.alibaba.druid.sql.dialect.postgresql.ast; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.ast.statement.SQLSelectQuery; +import com.alibaba.druid.sql.dialect.postgresql.visitor.PGASTVisitor; + +public class PGWithQuery extends PGSQLObjectImpl { + private static final long serialVersionUID = 1L; + private SQLExpr name; + private final List columns = new ArrayList(); + private SQLSelectQuery subQuery; + + public SQLExpr getName() { + return name; + } + + public void setName(SQLExpr name) { + this.name = name; + } + + public SQLSelectQuery getSubQuery() { + return subQuery; + } + + public void setSubQuery(SQLSelectQuery subQuery) { + this.subQuery = subQuery; + } + + public List getColumns() { + return columns; + } + + @Override + public void accept0(PGASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, name); + acceptChild(visitor, columns); + acceptChild(visitor, subQuery); + } + visitor.endVisit(this); + } +} \ No newline at end of file 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 6b3322f565..2860728409 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 @@ -104,6 +104,7 @@ public class PGLexer extends Lexer { map.put("IDENTITY", Token.IDENTITY); map.put("CASCADE", Token.CASCADE); map.put("RESTRICT", Token.RESTRICT); + map.put("USING", Token.USING); DEFAULT_MYSQL_KEYWORDS = new Keywords(map); } 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 e276ccf6c3..5793767f52 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 @@ -2,8 +2,11 @@ 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.statement.SQLDeleteStatement; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGDeleteStatement; import com.alibaba.druid.sql.dialect.postgresql.ast.PGTruncateStatement; import com.alibaba.druid.sql.parser.Lexer; import com.alibaba.druid.sql.parser.ParserException; @@ -11,45 +14,84 @@ import com.alibaba.druid.sql.parser.SQLStatementParser; import com.alibaba.druid.sql.parser.Token; public class PGSQLStatementParser extends SQLStatementParser { - public PGSQLStatementParser(String sql) throws ParserException { - this(new PGLexer(sql)); - this.lexer.nextToken(); - } - public PGSQLStatementParser(Lexer lexer) { - super(lexer); - } + public PGSQLStatementParser(String sql) throws ParserException{ + this(new PGLexer(sql)); + this.lexer.nextToken(); + } + + public PGSQLStatementParser(Lexer lexer){ + super(lexer); + } + + public PGSelectParser createSQLSelectParser() { + return new PGSelectParser(this.lexer); + } + + public SQLDeleteStatement parseDeleteStatement() throws ParserException { + lexer.nextToken(); + PGDeleteStatement deleteStatement = new PGDeleteStatement(); + + if (lexer.token() == (Token.FROM)) { + lexer.nextToken(); + } + if (lexer.token() == (Token.ONLY)) { + lexer.nextToken(); + deleteStatement.setOnly(true); + } + + SQLName tableName = exprParser.name(); + + deleteStatement.setTableName(tableName); + + if (lexer.token() == Token.USING) { + lexer.nextToken(); + for (;;) { + SQLName name = this.createExprParser().name(); + deleteStatement.getUsing().add(name); + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } + break; + } + } + + if (lexer.token() == (Token.WHERE)) { + lexer.nextToken(); + SQLExpr where = this.exprParser.expr(); + deleteStatement.setWhere(where); + } + + return deleteStatement; + } - public PGSelectParser createSQLSelectParser() { - return new PGSelectParser(this.lexer); - } - public SQLStatement parseTruncate() { accept(Token.TRUNCATE); - + PGTruncateStatement stmt = new PGTruncateStatement(); - + if (lexer.token() == Token.TABLE) { lexer.nextToken(); } - + if (lexer.token() == Token.ONLY) { lexer.nextToken(); stmt.setOnly(true); } - + for (;;) { SQLName name = this.exprParser.name(); stmt.getTableNames().add(name); - + if (lexer.token() == Token.COMMA) { lexer.nextToken(); continue; } - + break; } - + if (lexer.token() == Token.RESTART) { lexer.nextToken(); accept(Token.IDENTITY); @@ -59,7 +101,7 @@ public class PGSQLStatementParser extends SQLStatementParser { accept(Token.IDENTITY); stmt.setRestartIdentity(Boolean.FALSE); } - + if (lexer.token() == Token.CASCADE) { lexer.nextToken(); stmt.setCascade(Boolean.TRUE); @@ -67,17 +109,17 @@ public class PGSQLStatementParser extends SQLStatementParser { lexer.nextToken(); stmt.setCascade(Boolean.FALSE); } - - return stmt; + + return stmt; + } + + public boolean parseStatementListDialect(List statementList) { + if (lexer.token() == Token.WITH) { + SQLStatement stmt = parseSelect(); + statementList.add(stmt); + return true; + } + + return false; } - - public boolean parseStatementListDialect(List statementList) { - if (lexer.token() == Token.WITH) { - SQLStatement stmt = parseSelect(); - statementList.add(stmt); - return true; - } - - return false; - } } 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 72a236a765..44222503e0 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 @@ -6,7 +6,8 @@ import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; import com.alibaba.druid.sql.ast.statement.SQLSelectQuery; import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock; import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.IntoClause; -import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.WithQuery; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGWithClause; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGWithQuery; import com.alibaba.druid.sql.parser.Lexer; import com.alibaba.druid.sql.parser.ParserException; import com.alibaba.druid.sql.parser.SQLSelectParser; @@ -30,7 +31,7 @@ public class PGSelectParser extends SQLSelectParser { if (lexer.token() == Token.WITH) { lexer.nextToken(); - PGSelectQueryBlock.WithClause withClause = new PGSelectQueryBlock.WithClause(); + PGWithClause withClause = new PGWithClause(); if (lexer.token() == Token.RECURSIVE) { lexer.nextToken(); @@ -38,7 +39,7 @@ public class PGSelectParser extends SQLSelectParser { } for (;;) { - WithQuery withQuery = withQuery(); + PGWithQuery withQuery = withQuery(); withClause.getWithQuery().add(withQuery); if (lexer.token() == Token.COMMA) { lexer.nextToken(); @@ -220,8 +221,8 @@ public class PGSelectParser extends SQLSelectParser { return queryRest(queryBlock); } - private WithQuery withQuery() { - WithQuery withQuery = new WithQuery(); + private PGWithQuery withQuery() { + PGWithQuery withQuery = new PGWithQuery(); withQuery.setName(expr()); if (lexer.token() == Token.LPAREN) { 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 dc05dae3b5..b596f2d7cc 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 @@ -1,7 +1,11 @@ package com.alibaba.druid.sql.dialect.postgresql.visitor; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGCurrentOfExpr; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGDeleteStatement; import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock; import com.alibaba.druid.sql.dialect.postgresql.ast.PGTruncateStatement; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGWithClause; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGWithQuery; import com.alibaba.druid.sql.visitor.SQLASTVisitor; public interface PGASTVisitor extends SQLASTVisitor { @@ -18,13 +22,13 @@ public interface PGASTVisitor extends SQLASTVisitor { boolean visit(PGSelectQueryBlock.ForClause x); - void endVisit(PGSelectQueryBlock.WithQuery x); + void endVisit(PGWithQuery x); - boolean visit(PGSelectQueryBlock.WithQuery x); + boolean visit(PGWithQuery x); - void endVisit(PGSelectQueryBlock.WithClause x); + void endVisit(PGWithClause x); - boolean visit(PGSelectQueryBlock.WithClause x); + boolean visit(PGWithClause x); void endVisit(PGSelectQueryBlock.IntoClause x); @@ -33,4 +37,12 @@ public interface PGASTVisitor extends SQLASTVisitor { void endVisit(PGTruncateStatement x); boolean visit(PGTruncateStatement x); + + void endVisit(PGDeleteStatement x); + + boolean visit(PGDeleteStatement x); + + void endVisit(PGCurrentOfExpr x); + + boolean visit(PGCurrentOfExpr 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 83121db44f..c4d043f1e4 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 @@ -1,12 +1,14 @@ package com.alibaba.druid.sql.dialect.postgresql.visitor; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGCurrentOfExpr; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGDeleteStatement; import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.FetchClause; import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.ForClause; import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.IntoClause; import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.WindowClause; -import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.WithClause; -import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.WithQuery; import com.alibaba.druid.sql.dialect.postgresql.ast.PGTruncateStatement; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGWithClause; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGWithQuery; import com.alibaba.druid.sql.visitor.SQLASTVisitorAdapter; public class PGASTVisitorAdapter extends SQLASTVisitorAdapter implements PGASTVisitor { @@ -45,23 +47,23 @@ public class PGASTVisitorAdapter extends SQLASTVisitorAdapter implements PGASTVi } @Override - public void endVisit(WithQuery x) { + public void endVisit(PGWithQuery x) { } @Override - public boolean visit(WithQuery x) { + public boolean visit(PGWithQuery x) { return true; } @Override - public void endVisit(WithClause x) { + public void endVisit(PGWithClause x) { } @Override - public boolean visit(WithClause x) { + public boolean visit(PGWithClause x) { return true; } @@ -87,5 +89,26 @@ public class PGASTVisitorAdapter extends SQLASTVisitorAdapter implements PGASTVi return true; } + + @Override + public void endVisit(PGDeleteStatement x) { + + } + + @Override + public boolean visit(PGDeleteStatement x) { + + return true; + } + + @Override + public void endVisit(PGCurrentOfExpr x) { + + } + + @Override + public boolean visit(PGCurrentOfExpr 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 3a4a538651..bbe7e63e77 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 @@ -2,267 +2,320 @@ package com.alibaba.druid.sql.dialect.postgresql.visitor; import com.alibaba.druid.sql.ast.SQLSetQuantifier; import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGCurrentOfExpr; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGDeleteStatement; import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock; import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.FetchClause; import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.ForClause; import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.IntoClause; import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.WindowClause; -import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.WithClause; -import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.WithQuery; import com.alibaba.druid.sql.dialect.postgresql.ast.PGTruncateStatement; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGWithClause; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGWithQuery; import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor; -public class PGOutputVisitor extends SQLASTOutputVisitor implements - PGASTVisitor { +public class PGOutputVisitor extends SQLASTOutputVisitor implements PGASTVisitor { - public PGOutputVisitor(Appendable appender) { - super(appender); - } + public PGOutputVisitor(Appendable appender){ + super(appender); + } - @Override - public void endVisit(WindowClause x) { + @Override + public void endVisit(WindowClause x) { - } + } - @Override - public boolean visit(WindowClause x) { - print("WINDOW "); - x.getName().accept(this); - print(" AS "); - for (int i = 0; i < x.getDefinition().size(); ++i) { - if (i != 0) { - println(", "); - } - print("("); - x.getDefinition().get(i).accept(this); - print(")"); - } - return false; - } + @Override + public boolean visit(WindowClause x) { + print("WINDOW "); + x.getName().accept(this); + print(" AS "); + for (int i = 0; i < x.getDefinition().size(); ++i) { + if (i != 0) { + println(", "); + } + print("("); + x.getDefinition().get(i).accept(this); + print(")"); + } + return false; + } - @Override - public void endVisit(FetchClause x) { + @Override + public void endVisit(FetchClause x) { - } + } - @Override - public boolean visit(FetchClause x) { - print("FETCH "); - if (FetchClause.Option.FIRST.equals(x.getOption())) { - print("FIRST "); - } else if (FetchClause.Option.NEXT.equals(x.getOption())) { - print("NEXT "); - } - x.getCount().accept(this); - print(" ROWS ONLY"); - return false; - } + @Override + public boolean visit(FetchClause x) { + print("FETCH "); + if (FetchClause.Option.FIRST.equals(x.getOption())) { + print("FIRST "); + } else if (FetchClause.Option.NEXT.equals(x.getOption())) { + print("NEXT "); + } + x.getCount().accept(this); + print(" ROWS ONLY"); + return false; + } - @Override - public void endVisit(ForClause x) { + @Override + public void endVisit(ForClause x) { - } + } - @Override - public boolean visit(ForClause x) { - print("FOR "); - if (ForClause.Option.UPDATE.equals(x.getOption())) { - print("UPDATE "); - } else if (ForClause.Option.SHARE.equals(x.getOption())) { - print("SHARE "); - } + @Override + public boolean visit(ForClause x) { + print("FOR "); + if (ForClause.Option.UPDATE.equals(x.getOption())) { + print("UPDATE "); + } else if (ForClause.Option.SHARE.equals(x.getOption())) { + print("SHARE "); + } - if (x.getOf().size() > 0) { - for (int i = 0; i < x.getOf().size(); ++i) { - if (i != 0) { - println(", "); - } - x.getOf().get(i).accept(this); - } - } - - if (x.isNoWait()) { - print(" NOWAIT"); - } + if (x.getOf().size() > 0) { + for (int i = 0; i < x.getOf().size(); ++i) { + if (i != 0) { + println(", "); + } + x.getOf().get(i).accept(this); + } + } - return false; - } + if (x.isNoWait()) { + print(" NOWAIT"); + } - @Override - public void endVisit(WithQuery x) { + return false; + } - } + @Override + public void endVisit(PGWithQuery x) { - @Override - public boolean visit(WithQuery x) { - x.getName().accept(this); + } - if (x.getColumns().size() > 0) { - print(" ("); - printAndAccept(x.getColumns(), ", "); - print(")"); - } - println(); - print("AS"); - println(); - print("("); - incrementIndent(); - println(); - x.getSubQuery().accept(this); - decrementIndent(); - println(); - print(")"); + @Override + public boolean visit(PGWithQuery x) { + x.getName().accept(this); - return false; - } + if (x.getColumns().size() > 0) { + print(" ("); + printAndAccept(x.getColumns(), ", "); + print(")"); + } + println(); + print("AS"); + println(); + print("("); + incrementIndent(); + println(); + x.getSubQuery().accept(this); + decrementIndent(); + println(); + print(")"); - @Override - public void endVisit(WithClause x) { + return false; + } - } + @Override + public void endVisit(PGWithClause x) { - @Override - public boolean visit(WithClause x) { - print("WITH"); - incrementIndent(); - println(); - printlnAndAccept(x.getWithQuery(), ", "); - decrementIndent(); - return false; - } + } - public boolean visit(SQLSelectQueryBlock x) { - if (x instanceof PGSelectQueryBlock) { - return visit((PGSelectQueryBlock) x); - } + @Override + public boolean visit(PGWithClause x) { + print("WITH"); + incrementIndent(); + println(); + printlnAndAccept(x.getWithQuery(), ", "); + decrementIndent(); + return false; + } - return super.visit(x); - } + public boolean visit(SQLSelectQueryBlock x) { + if (x instanceof PGSelectQueryBlock) { + return visit((PGSelectQueryBlock) x); + } - public boolean visit(PGSelectQueryBlock x) { - if (x.getWith() != null) { - x.getWith().accept(this); - println(); - } + return super.visit(x); + } - print("SELECT "); + public boolean visit(PGSelectQueryBlock x) { + if (x.getWith() != null) { + x.getWith().accept(this); + println(); + } - if (SQLSetQuantifier.ALL == x.getDistionOption()) { - print("ALL "); - } else if (SQLSetQuantifier.DISTINCT == x.getDistionOption()) { - print("DISTINCT "); + print("SELECT "); - if (x.getDistinctOn() != null) { - print("ON "); - printAndAccept(x.getDistinctOn(), ", "); - } - } + if (SQLSetQuantifier.ALL == x.getDistionOption()) { + print("ALL "); + } else if (SQLSetQuantifier.DISTINCT == x.getDistionOption()) { + print("DISTINCT "); - printSelectList(x.getSelectList()); - - if (x.getInto() != null) { - println(); - x.getInto().accept(this); - } + if (x.getDistinctOn() != null) { + print("ON "); + printAndAccept(x.getDistinctOn(), ", "); + } + } - if (x.getFrom() != null) { - println(); - print("FROM "); - x.getFrom().accept(this); - } + printSelectList(x.getSelectList()); - if (x.getWhere() != null) { - println(); - print("WHERE "); - x.getWhere().accept(this); - } + if (x.getInto() != null) { + println(); + x.getInto().accept(this); + } - if (x.getGroupBy() != null) { - print(" "); - x.getGroupBy().accept(this); - } + if (x.getFrom() != null) { + println(); + print("FROM "); + x.getFrom().accept(this); + } - if (x.getWindow() != null) { - println(); - x.getWindow().accept(this); - } + if (x.getWhere() != null) { + println(); + print("WHERE "); + x.getWhere().accept(this); + } - if (x.getOrderBy() != null) { - println(); - x.getOrderBy().accept(this); - } + if (x.getGroupBy() != null) { + print(" "); + x.getGroupBy().accept(this); + } - if (x.getLimit() != null) { - println(); - print("LIMIT "); - x.getLimit().accept(this); - } + if (x.getWindow() != null) { + println(); + x.getWindow().accept(this); + } - if (x.getOffset() != null) { - println(); - print("OFFSET "); - x.getOffset().accept(this); - print(" ROWS"); - } + if (x.getOrderBy() != null) { + println(); + x.getOrderBy().accept(this); + } - if (x.getFetch() != null) { - println(); - x.getFetch().accept(this); - } + if (x.getLimit() != null) { + println(); + print("LIMIT "); + x.getLimit().accept(this); + } - if (x.getForClause() != null) { - println(); - x.getForClause().accept(this); - } + if (x.getOffset() != null) { + println(); + print("OFFSET "); + x.getOffset().accept(this); + print(" ROWS"); + } - return false; - } + if (x.getFetch() != null) { + println(); + x.getFetch().accept(this); + } - @Override - public void endVisit(IntoClause x) { - - } + if (x.getForClause() != null) { + println(); + x.getForClause().accept(this); + } - @Override - public boolean visit(IntoClause x) { - print("INTO "); - if (x.getOption() != null) { - print(x.getOption().name()); - print(" "); - } - x.getTable().accept(this); - return false; - } - - @Override - public void endVisit(PGTruncateStatement x) { - - } - - @Override - public boolean visit(PGTruncateStatement x) { - print("TRUNCATE TABLE "); - if (x.isOnly()) { - print("ONLY "); - } - - printlnAndAccept(x.getTableNames(), ", "); - - if (x.getRestartIdentity() != null) { - if (x.getRestartIdentity().booleanValue()) { - print(" RESTART IDENTITY"); - } else { - print(" CONTINUE IDENTITY"); - } - } - - if (x.getCascade() != null) { + return false; + } + + @Override + public void endVisit(IntoClause x) { + + } + + @Override + public boolean visit(IntoClause x) { + print("INTO "); + if (x.getOption() != null) { + print(x.getOption().name()); + print(" "); + } + x.getTable().accept(this); + return false; + } + + @Override + public void endVisit(PGTruncateStatement x) { + + } + + @Override + public boolean visit(PGTruncateStatement x) { + print("TRUNCATE TABLE "); + if (x.isOnly()) { + print("ONLY "); + } + + printlnAndAccept(x.getTableNames(), ", "); + + if (x.getRestartIdentity() != null) { + if (x.getRestartIdentity().booleanValue()) { + print(" RESTART IDENTITY"); + } else { + print(" CONTINUE IDENTITY"); + } + } + + if (x.getCascade() != null) { if (x.getCascade().booleanValue()) { print(" CASCADE"); } else { print(" RESTRICT"); } } - return false; - } + return false; + } + + @Override + public void endVisit(PGDeleteStatement x) { + + } + + @Override + public boolean visit(PGDeleteStatement x) { + if (x.getWith() != null) { + x.getWith().accept(this); + println(); + } + + print("DELETE FROM "); + + if (x.isOnly()) { + print("ONLY "); + } + + x.getTableName().accept(this); + + if (x.getAlias() != null) { + print(" AS "); + print(x.getAlias()); + } + + if (x.getUsing().size() > 0) { + println(); + print("USING "); + printAndAccept(x.getUsing(), ", "); + } + + if (x.getWhere() != null) { + println(); + print("WHERE "); + x.getWhere().accept(this); + } + + return false; + } + + @Override + public void endVisit(PGCurrentOfExpr x) { + + } + + @Override + public boolean visit(PGCurrentOfExpr x) { + print("CURRENT OF "); + x.getCursor().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 2b29044df0..16ec0e01c5 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 @@ -1,15 +1,23 @@ package com.alibaba.druid.sql.dialect.postgresql.visitor; +import java.util.HashMap; +import java.util.Map; + +import com.alibaba.druid.sql.ast.SQLName; +import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; import com.alibaba.druid.sql.ast.statement.SQLTruncateStatement; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGCurrentOfExpr; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGDeleteStatement; import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.FetchClause; import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.ForClause; import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.IntoClause; import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.WindowClause; -import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.WithClause; -import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock.WithQuery; import com.alibaba.druid.sql.dialect.postgresql.ast.PGTruncateStatement; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGWithClause; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGWithQuery; import com.alibaba.druid.sql.visitor.SchemaStatVisitor; import com.alibaba.druid.stat.TableStat; +import com.alibaba.druid.stat.TableStat.Mode; public class PGSchemaStatVisitor extends SchemaStatVisitor implements PGASTVisitor { @@ -45,23 +53,23 @@ public class PGSchemaStatVisitor extends SchemaStatVisitor implements PGASTVisit } @Override - public void endVisit(WithQuery x) { + public void endVisit(PGWithQuery x) { } @Override - public boolean visit(WithQuery x) { + public boolean visit(PGWithQuery x) { return true; } @Override - public void endVisit(WithClause x) { + public void endVisit(PGWithClause x) { } @Override - public boolean visit(WithClause x) { + public boolean visit(PGWithClause x) { return true; } @@ -94,4 +102,65 @@ public class PGSchemaStatVisitor extends SchemaStatVisitor implements PGASTVisit this.visit((SQLTruncateStatement) x); return false; } + + @Override + public void endVisit(PGDeleteStatement x) { + + } + + @Override + public boolean visit(PGDeleteStatement x) { + if (x.getWith() != null) { + x.getWith().accept(this); + } + + aliasLocal.set(new HashMap()); + + for (SQLName name : x.getUsing()) { + String ident = name.toString(); + + TableStat stat = tableStats.get(ident); + if (stat == null) { + stat = new TableStat(); + tableStats.put(new TableStat.Name(ident), stat); + } + stat.incrementSelectCount(); + + Map aliasMap = aliasLocal.get(); + if (aliasMap != null) { + aliasMap.put(ident, ident); + } + } + + + x.putAttribute("_original_use_mode", modeLocal.get()); + modeLocal.set(Mode.Delete); + + String ident = ((SQLIdentifierExpr) x.getTableName()).getName(); + currentTableLocal.set(ident); + + TableStat stat = tableStats.get(ident); + if (stat == null) { + stat = new TableStat(); + tableStats.put(new TableStat.Name(ident), stat); + if (x.getAlias() != null) { + tableStats.put(new TableStat.Name(x.getAlias()), stat); + } + } + stat.incrementDeleteCount(); + + accept(x.getWhere()); + + return false; + } + + @Override + public void endVisit(PGCurrentOfExpr x) { + + } + + @Override + public boolean visit(PGCurrentOfExpr x) { + return false; + } } diff --git a/src/main/java/com/alibaba/druid/sql/parser/Token.java b/src/main/java/com/alibaba/druid/sql/parser/Token.java index 69189a70a3..04d4f20a85 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/Token.java +++ b/src/main/java/com/alibaba/druid/sql/parser/Token.java @@ -124,6 +124,7 @@ public enum Token { CONTINUE("CONTINUE"), CASCADE("CASCADE"), RESTRICT("RESTRICT"), + USING("USING"), // oracle START("START"), diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java b/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java index 556a367015..6f0e3f9617 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java @@ -350,8 +350,6 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { x.putAttribute("_original_use_mode", modeLocal.get()); modeLocal.set(Mode.Delete); - aliasLocal.set(new HashMap()); - String ident = ((SQLIdentifierExpr) x.getTableName()).getName(); currentTableLocal.set(ident); diff --git a/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGDeleteTest.java b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGDeleteTest.java new file mode 100644 index 0000000000..22dccc427b --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGDeleteTest.java @@ -0,0 +1,39 @@ +package com.alibaba.druid.bvt.sql.postgresql; + +import java.util.List; + +import junit.framework.Assert; + +import com.alibaba.druid.sql.PGTest; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.postgresql.parser.PGSQLStatementParser; +import com.alibaba.druid.sql.dialect.postgresql.visitor.PGSchemaStatVisitor; +import com.alibaba.druid.stat.TableStat; +import com.alibaba.druid.stat.TableStat.Column; + +public class PGDeleteTest extends PGTest { + + public void test_0() throws Exception { + String sql = "DELETE FROM films USING producers WHERE producer_id = producers.id AND producers.name = 'foo';"; + + PGSQLStatementParser parser = new PGSQLStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement statemen = statementList.get(0); + System.out.println(output(statementList)); + + Assert.assertEquals(1, statementList.size()); + + PGSchemaStatVisitor visitor = new PGSchemaStatVisitor(); + statemen.accept(visitor); + + System.out.println("Tables : " + visitor.getTables()); + System.out.println("fields : " + visitor.getFields()); + + Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("films"))); + Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("producers"))); + + //Assert.assertTrue(visitor.getFields().size() == 0); + } + + +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGDeleteTest2.java b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGDeleteTest2.java new file mode 100644 index 0000000000..c176044aaa --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGDeleteTest2.java @@ -0,0 +1,37 @@ +package com.alibaba.druid.bvt.sql.postgresql; + +import java.util.List; + +import junit.framework.Assert; + +import com.alibaba.druid.sql.PGTest; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.postgresql.parser.PGSQLStatementParser; +import com.alibaba.druid.sql.dialect.postgresql.visitor.PGSchemaStatVisitor; +import com.alibaba.druid.stat.TableStat; + +public class PGDeleteTest2 extends PGTest { + + public void test_0() throws Exception { + String sql = "DELETE FROM tasks WHERE CURRENT OF c_tasks;"; + + PGSQLStatementParser parser = new PGSQLStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement statemen = statementList.get(0); + System.out.println(output(statementList)); + + Assert.assertEquals(1, statementList.size()); + + PGSchemaStatVisitor visitor = new PGSchemaStatVisitor(); + statemen.accept(visitor); + + System.out.println("Tables : " + visitor.getTables()); + System.out.println("fields : " + visitor.getFields()); + + Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("tasks"))); + + //Assert.assertTrue(visitor.getFields().size() == 0); + } + + +}