add postgresql parser support

This commit is contained in:
温少
2012-02-21 21:47:09 +08:00
parent 0979d5d12b
commit 769ed41296
8 changed files with 665 additions and 0 deletions
@@ -0,0 +1,9 @@
package com.alibaba.druid.sql.dialect.postgresql.ast;
import com.alibaba.druid.sql.ast.SQLObject;
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGASTVisitor;
public interface PGSQLObject extends SQLObject {
void accept0(PGASTVisitor visitor);
}
@@ -0,0 +1,36 @@
/*
* Copyright 1999-2011 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;
import com.alibaba.druid.sql.ast.SQLObjectImpl;
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGASTVisitor;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public abstract class PGSQLObjectImpl extends SQLObjectImpl implements PGSQLObject {
private static final long serialVersionUID = 1L;
public PGSQLObjectImpl(){
}
@Override
protected void accept0(SQLASTVisitor visitor) {
this.accept0((PGASTVisitor) visitor);
}
public abstract void accept0(PGASTVisitor visitor);
}
@@ -0,0 +1,235 @@
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.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;
public class PGSelectQueryBlock extends SQLSelectQueryBlock {
private static final long serialVersionUID = 1L;
private WithClause with;
private List<SQLExpr> distinctOn = new ArrayList<SQLExpr>(2);
private SQLExpr limit;
private SQLExpr offset;
private SQLOrderBy orderBy;
public WithClause getWith() {
return with;
}
public void setWith(WithClause with) {
this.with = with;
}
public SQLExpr getLimit() {
return limit;
}
public void setLimit(SQLExpr limit) {
this.limit = limit;
}
public SQLOrderBy getOrderBy() {
return orderBy;
}
public void setOrderBy(SQLOrderBy orderBy) {
this.orderBy = orderBy;
}
public SQLExpr getOffset() {
return offset;
}
public void setOffset(SQLExpr offset) {
this.offset = offset;
}
public List<SQLExpr> getDistinctOn() {
return distinctOn;
}
public void setDistinctOn(List<SQLExpr> distinctOn) {
this.distinctOn = distinctOn;
}
public static class WindowClause extends PGSQLObjectImpl {
private static final long serialVersionUID = 1L;
private SQLExpr name;
private List<SQLExpr> definition = new ArrayList<SQLExpr>(2);
public SQLExpr getName() {
return name;
}
public void setName(SQLExpr name) {
this.name = name;
}
public List<SQLExpr> getDefinition() {
return definition;
}
public void setDefinition(List<SQLExpr> definition) {
this.definition = definition;
}
@Override
public void accept0(PGASTVisitor visitor) {
if (visitor.visit(this)) {
acceptChild(visitor, name);
acceptChild(visitor, definition);
}
}
}
public static class FetchClause extends PGSQLObjectImpl {
private static final long serialVersionUID = 1L;
public static enum Option {
FIRST, NEXT
}
private Option option;
private SQLExpr count;
public Option getOption() {
return option;
}
public void setOption(Option option) {
this.option = option;
}
public SQLExpr getCount() {
return count;
}
public void setCount(SQLExpr count) {
this.count = count;
}
@Override
public void accept0(PGASTVisitor visitor) {
if (visitor.visit(this)) {
acceptChild(visitor, count);
}
}
}
public static class ForClause extends PGSQLObjectImpl {
private static final long serialVersionUID = 1L;
public static enum Option {
UPDATE, SHARE
}
private List<SQLExpr> of = new ArrayList<SQLExpr>(2);
private boolean noWait;
private Option option;
public Option getOption() {
return option;
}
public void setOption(Option option) {
this.option = option;
}
public List<SQLExpr> getOf() {
return of;
}
public void setOf(List<SQLExpr> of) {
this.of = of;
}
public boolean isNoWait() {
return noWait;
}
public void setNoWait(boolean noWait) {
this.noWait = noWait;
}
@Override
public void accept0(PGASTVisitor visitor) {
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> withQuery = new ArrayList<WithQuery>(2);
public boolean isRecursive() {
return recursive;
}
public void setRecursive(boolean recursive) {
this.recursive = recursive;
}
public List<WithQuery> getWithQuery() {
return withQuery;
}
public void setWithQuery(List<WithQuery> 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<SQLExpr> columns = new ArrayList<SQLExpr>();
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<SQLExpr> getColumns() {
return columns;
}
@Override
public void accept0(PGASTVisitor visitor) {
if (visitor.visit(this)) {
acceptChild(visitor, name);
acceptChild(visitor, columns);
acceptChild(visitor, subQuery);
}
}
}
}
@@ -0,0 +1,105 @@
package com.alibaba.druid.sql.dialect.postgresql.parser;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.druid.sql.parser.Keywords;
import com.alibaba.druid.sql.parser.Lexer;
import com.alibaba.druid.sql.parser.Token;
public class PGLexer extends Lexer {
public final static Keywords DEFAULT_MYSQL_KEYWORDS;
static {
Map<String, Token> map = new HashMap<String, Token>();
map.put("EXISTS", Token.EXISTS);
map.put("THEN", Token.THEN);
map.put("AS", Token.AS);
map.put("GROUP", Token.GROUP);
map.put("BY", Token.BY);
map.put("HAVING", Token.HAVING);
map.put("DELETE", Token.DELETE);
map.put("ORDER", Token.ORDER);
map.put("INDEX", Token.INDEX);
map.put("FOR", Token.FOR);
map.put("SCHEMA", Token.SCHEMA);
map.put("FOREIGN", Token.FOREIGN);
map.put("REFERENCE", Token.REFERENCE);
map.put("REFERENCES", Token.REFERENCES);
map.put("CHECK", Token.CHECK);
map.put("PRIMARY", Token.PRIMARY);
map.put("KEY", Token.KEY);
map.put("CONSTRAINT", Token.CONSTRAINT);
map.put("DEFAULT", Token.DEFAULT);
map.put("VIEW", Token.VIEW);
map.put("CREATE", Token.CREATE);
map.put("VALUES", Token.VALUES);
map.put("ALTER", Token.ALTER);
map.put("TABLE", Token.TABLE);
map.put("DROP", Token.DROP);
map.put("SET", Token.SET);
map.put("INTO", Token.INTO);
map.put("UPDATE", Token.UPDATE);
map.put("NULL", Token.NULL);
map.put("IS", Token.IS);
map.put("NOT", Token.NOT);
map.put("SELECT", Token.SELECT);
map.put("INSERT", Token.INSERT);
map.put("FROM", Token.FROM);
map.put("WHERE", Token.WHERE);
map.put("AND", Token.AND);
map.put("OR", Token.OR);
map.put("XOR", Token.XOR);
map.put("DISTINCT", Token.DISTINCT);
map.put("UNIQUE", Token.UNIQUE);
map.put("ALL", Token.ALL);
map.put("UNION", Token.UNION);
map.put("INTERSECT", Token.INTERSECT);
map.put("MINUS", Token.MINUS);
map.put("INNER", Token.INNER);
map.put("LEFT", Token.LEFT);
map.put("RIGHT", Token.RIGHT);
map.put("FULL", Token.FULL);
map.put("ON", Token.ON);
map.put("OUTER", Token.OUTER);
map.put("JOIN", Token.JOIN);
map.put("NEW", Token.NEW);
map.put("CASE", Token.CASE);
map.put("WHEN", Token.WHEN);
map.put("END", Token.END);
map.put("WHEN", Token.WHEN);
map.put("ELSE", Token.ELSE);
map.put("EXISTS", Token.EXISTS);
map.put("CAST", Token.CAST);
map.put("IN", Token.IN);
map.put("ASC", Token.ASC);
map.put("DESC", Token.DESC);
map.put("LIKE", Token.LIKE);
map.put("ESCAPE", Token.ESCAPE);
map.put("BETWEEN", Token.BETWEEN);
map.put("INTERVAL", Token.INTERVAL);
map.put("LOCK", Token.LOCK);
map.put("SOME", Token.SOME);
map.put("ANY", Token.ANY);
map.put("LIMIT", Token.LIMIT);
map.put("OFFSET", Token.OFFSET);
map.put("WINDOW", Token.WINDOW);
map.put("ROW", Token.ROW);
map.put("ROWS", Token.ROWS);
map.put("ONLY", Token.ONLY);
map.put("FIRST", Token.FIRST);
map.put("NEXT", Token.NEXT);
map.put("FETCH", Token.FETCH);
map.put("OF", Token.OF);
map.put("SHARE", Token.SHARE);
map.put("NOWAIT", Token.NOWAIT);
map.put("RECURSIVE", Token.RECURSIVE);
DEFAULT_MYSQL_KEYWORDS = new Keywords(map);
}
public PGLexer(String input){
super(input);
super.keywods = DEFAULT_MYSQL_KEYWORDS;
}
}
@@ -0,0 +1,20 @@
package com.alibaba.druid.sql.dialect.postgresql.parser;
import com.alibaba.druid.sql.parser.Lexer;
import com.alibaba.druid.sql.parser.ParserException;
import com.alibaba.druid.sql.parser.SQLStatementParser;
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 PGSelectParser createSQLSelectParser() {
return new PGSelectParser(this.lexer);
}
}
@@ -0,0 +1,220 @@
package com.alibaba.druid.sql.dialect.postgresql.parser;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLSetQuantifier;
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.WithQuery;
import com.alibaba.druid.sql.parser.Lexer;
import com.alibaba.druid.sql.parser.ParserException;
import com.alibaba.druid.sql.parser.SQLSelectParser;
import com.alibaba.druid.sql.parser.Token;
public class PGSelectParser extends SQLSelectParser {
public PGSelectParser(Lexer lexer) {
super(lexer);
}
public PGSelectParser(String sql) throws ParserException {
this(new PGLexer(sql));
this.lexer.nextToken();
}
@Override
protected SQLSelectQuery query() throws ParserException {
PGSelectQueryBlock queryBlock = new PGSelectQueryBlock();
if (lexer.token() == Token.WITH) {
lexer.nextToken();
PGSelectQueryBlock.WithClause withClause = new PGSelectQueryBlock.WithClause();
if (lexer.token() == Token.RECURSIVE) {
lexer.nextToken();
withClause.setRecursive(true);
}
for (;;) {
WithQuery withQuery = withQuery();
withClause.getWithQuery().add(withQuery);
if (lexer.token() == Token.COMMA) {
lexer.nextToken();
continue;
} else {
break;
}
}
queryBlock.setWith(withClause);
}
accept(Token.SELECT);
if (lexer.token() == Token.DISTINCT) {
queryBlock.setDistionOption(SQLSetQuantifier.DISTINCT);
lexer.nextToken();
if (lexer.token() == Token.ON) {
lexer.nextToken();
for (;;) {
SQLExpr expr = this.createExprParser().expr();
queryBlock.getDistinctOn().add(expr);
if (lexer.token() == Token.COMMA) {
lexer.nextToken();
continue;
} else {
break;
}
}
}
} else if (lexer.token() == Token.ALL) {
queryBlock.setDistionOption(SQLSetQuantifier.ALL);
lexer.nextToken();
}
parseFrom(queryBlock);
parseWhere(queryBlock);
parseGroupBy(queryBlock);
if (lexer.token() == Token.WINDOW) {
lexer.nextToken();
PGSelectQueryBlock.WindowClause window = new PGSelectQueryBlock.WindowClause();
window.setName(this.expr());
accept(Token.AS);
for (;;) {
SQLExpr expr = this.createExprParser().expr();
window.getDefinition().add(expr);
if (lexer.token() == Token.COMMA) {
lexer.nextToken();
continue;
} else {
break;
}
}
}
queryBlock.setOrderBy(this.createExprParser().parseOrderBy());
if (lexer.token() == Token.LIMIT) {
lexer.nextToken();
if (lexer.token() == Token.ALL) {
queryBlock.setLimit(new SQLIdentifierExpr("ALL"));
lexer.nextToken();
} else {
SQLExpr limit = expr();
queryBlock.setLimit(limit);
}
}
if (lexer.token() == Token.OFFSET) {
lexer.nextToken();
SQLExpr offset = expr();
queryBlock.setOffset(offset);
if (lexer.token() == Token.ROW || lexer.token() == Token.ROWS) {
lexer.nextToken();
} else {
throw new ParserException("expect 'ROW' or 'ROWS'");
}
}
if (lexer.token() == Token.FETCH) {
lexer.nextToken();
PGSelectQueryBlock.FetchClause fetch = new PGSelectQueryBlock.FetchClause();
if (lexer.token() == Token.FIRST) {
fetch.setOption(PGSelectQueryBlock.FetchClause.Option.FIRST);
} else if (lexer.token() == Token.NEXT) {
fetch.setOption(PGSelectQueryBlock.FetchClause.Option.NEXT);
} else {
throw new ParserException("expect 'FIRST' or 'NEXT'");
}
SQLExpr count = expr();
fetch.setCount(count);
if (lexer.token() == Token.ROW || lexer.token() == Token.ROWS) {
lexer.nextToken();
} else {
throw new ParserException("expect 'ROW' or 'ROWS'");
}
if (lexer.token() == Token.ONLY) {
lexer.nextToken();
} else {
throw new ParserException("expect 'ONLY'");
}
}
if (lexer.token() == Token.FOR) {
lexer.nextToken();
PGSelectQueryBlock.ForClause forClause = new PGSelectQueryBlock.ForClause();
if (lexer.token() == Token.UPDATE) {
forClause.setOption(PGSelectQueryBlock.ForClause.Option.UPDATE);
} else if (lexer.token() == Token.SHARE) {
forClause.setOption(PGSelectQueryBlock.ForClause.Option.SHARE);
} else {
throw new ParserException("expect 'FIRST' or 'NEXT'");
}
accept(Token.OF);
for (;;) {
SQLExpr expr = this.createExprParser().expr();
forClause.getOf().add(expr);
if (lexer.token() == Token.COMMA) {
lexer.nextToken();
continue;
} else {
break;
}
}
if (lexer.token() == Token.NOWAIT) {
lexer.nextToken();
forClause.setNoWait(true);
}
}
return queryBlock;
}
private WithQuery withQuery() {
WithQuery withQuery = new WithQuery();
withQuery.setName(expr());
if (lexer.token() == Token.LPAREN) {
lexer.nextToken();
for (;;) {
SQLExpr expr = this.createExprParser().expr();
withQuery.getColumns().add(expr);
if (lexer.token() == Token.COMMA) {
lexer.nextToken();
continue;
} else {
break;
}
}
accept(Token.RPAREN);
}
accept(Token.AS);
if (lexer.token() == Token.LPAREN) {
SQLSelectQuery subQuery = query();
withQuery.setSubQuery(subQuery);
accept(Token.RPAREN);
}
return withQuery;
}
}
@@ -0,0 +1,26 @@
package com.alibaba.druid.sql.dialect.postgresql.visitor;
import com.alibaba.druid.sql.dialect.postgresql.ast.PGSelectQueryBlock;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public interface PGASTVisitor extends SQLASTVisitor {
void endVisit(PGSelectQueryBlock.WindowClause x);
boolean visit(PGSelectQueryBlock.WindowClause x);
void endVisit(PGSelectQueryBlock.FetchClause x);
boolean visit(PGSelectQueryBlock.FetchClause x);
void endVisit(PGSelectQueryBlock.ForClause x);
boolean visit(PGSelectQueryBlock.ForClause x);
void endVisit(PGSelectQueryBlock.WithQuery x);
boolean visit(PGSelectQueryBlock.WithQuery x);
void endVisit(PGSelectQueryBlock.WithClause x);
boolean visit(PGSelectQueryBlock.WithClause x);
}
@@ -99,6 +99,20 @@ public enum Token {
LIMIT("LIMIT"),
KILL("KILL"),
//postgresql
WINDOW("WINDOW"),
OFFSET("OFFSET"),
ROW("ROW"),
ROWS("ROWS"),
ONLY("ONLY"),
FIRST("FIRST"),
NEXT("NEXT"),
FETCH("FETCH"),
OF("OF"),
SHARE("SHARE"),
NOWAIT("NOWAIT"),
RECURSIVE("RECURSIVE"),
// oracle
START("START"),
PRIOR("PRIOR"),