mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
feat: 增加多支持presto分页的语法
This commit is contained in:
@@ -43,6 +43,7 @@ import com.alibaba.druid.sql.dialect.oracle.visitor.OracleSchemaStatVisitor;
|
||||
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleToMySqlOutputVisitor;
|
||||
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGOutputVisitor;
|
||||
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGSchemaStatVisitor;
|
||||
import com.alibaba.druid.sql.dialect.presto.visitor.PrestoOutputVisitor;
|
||||
import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerOutputVisitor;
|
||||
import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerSchemaStatVisitor;
|
||||
import com.alibaba.druid.sql.parser.*;
|
||||
@@ -499,6 +500,8 @@ public class SQLUtils {
|
||||
return new BlinkOutputVisitor(out);
|
||||
case antspark:
|
||||
return new AntsparkOutputVisitor(out);
|
||||
case presto:
|
||||
return new PrestoOutputVisitor(out);
|
||||
case clickhouse:
|
||||
return new ClickhouseOutputVisitor(out);
|
||||
default:
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.presto.ast.stmt;
|
||||
|
||||
import com.alibaba.druid.DbType;
|
||||
import com.alibaba.druid.sql.ast.SQLStatement;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelect;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
|
||||
import com.alibaba.druid.sql.dialect.presto.visitor.PrestoVisitor;
|
||||
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
|
||||
|
||||
/**
|
||||
* presto 的 select语句
|
||||
*
|
||||
* @author zhangcanlong
|
||||
* @date 2022/01/11
|
||||
*/
|
||||
public class PrestoSelectStatement extends SQLSelectStatement implements SQLStatement {
|
||||
|
||||
public PrestoSelectStatement() {
|
||||
super(DbType.postgresql);
|
||||
}
|
||||
|
||||
public PrestoSelectStatement(SQLSelect select) {
|
||||
super(select, DbType.postgresql);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void accept0(SQLASTVisitor visitor) {
|
||||
if (visitor instanceof PrestoVisitor) {
|
||||
this.accept0((PrestoVisitor) visitor);
|
||||
} else {
|
||||
super.accept0(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
public void accept0(PrestoVisitor visitor) {
|
||||
if (visitor.visit(this)) {
|
||||
this.acceptChild(visitor, this.select);
|
||||
}
|
||||
visitor.endVisit(this);
|
||||
}
|
||||
}
|
||||
@@ -16,13 +16,9 @@
|
||||
package com.alibaba.druid.sql.dialect.presto.parser;
|
||||
|
||||
import com.alibaba.druid.DbType;
|
||||
import com.alibaba.druid.sql.ast.SQLExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLIntervalExpr;
|
||||
import com.alibaba.druid.sql.ast.expr.SQLIntervalUnit;
|
||||
import com.alibaba.druid.sql.dialect.phoenix.parser.PhoenixLexer;
|
||||
import com.alibaba.druid.sql.parser.*;
|
||||
import com.alibaba.druid.sql.parser.Lexer;
|
||||
import com.alibaba.druid.sql.parser.SQLExprParser;
|
||||
import com.alibaba.druid.sql.parser.SQLParserFeature;
|
||||
|
||||
/**
|
||||
* Created by wenshao on 16/9/13.
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* 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.presto.parser;
|
||||
|
||||
import com.alibaba.druid.DbType;
|
||||
import com.alibaba.druid.sql.ast.SQLExpr;
|
||||
import com.alibaba.druid.sql.ast.SQLLimit;
|
||||
import com.alibaba.druid.sql.ast.SQLObject;
|
||||
import com.alibaba.druid.sql.ast.SQLSetQuantifier;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectQuery;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
|
||||
import com.alibaba.druid.sql.parser.SQLExprParser;
|
||||
import com.alibaba.druid.sql.parser.SQLSelectListCache;
|
||||
import com.alibaba.druid.sql.parser.SQLSelectParser;
|
||||
import com.alibaba.druid.sql.parser.Token;
|
||||
import com.alibaba.druid.util.FnvHash;
|
||||
|
||||
/**
|
||||
* presto的 选择解析器
|
||||
*
|
||||
* @author zhangcanlong
|
||||
* @date 2022/01/11
|
||||
*/
|
||||
public class PrestoSelectParser extends SQLSelectParser {
|
||||
|
||||
public PrestoSelectParser(SQLExprParser exprParser) {
|
||||
super(exprParser);
|
||||
}
|
||||
|
||||
public PrestoSelectParser(SQLExprParser exprParser, SQLSelectListCache selectListCache) {
|
||||
super(exprParser, selectListCache);
|
||||
}
|
||||
|
||||
public PrestoSelectParser(String sql) {
|
||||
this(new PrestoExprParser(sql));
|
||||
}
|
||||
|
||||
protected SQLExprParser createExprParser() {
|
||||
return new PrestoExprParser(this.lexer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SQLSelectQuery query(SQLObject parent, boolean acceptUnion) {
|
||||
if (this.lexer.token() == Token.LPAREN) {
|
||||
this.lexer.nextToken();
|
||||
|
||||
SQLSelectQuery select = this.query();
|
||||
this.accept(Token.RPAREN);
|
||||
|
||||
return this.queryRest(select, acceptUnion);
|
||||
}
|
||||
|
||||
if (this.lexer.token() == Token.VALUES) {
|
||||
return this.valuesQuery(acceptUnion);
|
||||
}
|
||||
|
||||
SQLSelectQueryBlock queryBlock = new SQLSelectQueryBlock(this.dbType);
|
||||
|
||||
if (this.lexer.hasComment() && this.lexer.isKeepComments()) {
|
||||
queryBlock.addBeforeComment(this.lexer.readAndResetComments());
|
||||
}
|
||||
|
||||
this.accept(Token.SELECT);
|
||||
|
||||
if (this.lexer.token() == Token.HINT) {
|
||||
this.exprParser.parseHints(queryBlock.getHints());
|
||||
}
|
||||
|
||||
if (this.lexer.token() == Token.COMMENT) {
|
||||
this.lexer.nextToken();
|
||||
}
|
||||
|
||||
if (DbType.informix == this.dbType) {
|
||||
if (this.lexer.identifierEquals(FnvHash.Constants.SKIP)) {
|
||||
this.lexer.nextToken();
|
||||
SQLExpr offset = this.exprParser.primary();
|
||||
queryBlock.setOffset(offset);
|
||||
}
|
||||
|
||||
if (this.lexer.identifierEquals(FnvHash.Constants.FIRST)) {
|
||||
this.lexer.nextToken();
|
||||
SQLExpr first = this.exprParser.primary();
|
||||
queryBlock.setFirst(first);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.lexer.token() == Token.DISTINCT) {
|
||||
queryBlock.setDistionOption(SQLSetQuantifier.DISTINCT);
|
||||
this.lexer.nextToken();
|
||||
} else if (this.lexer.token() == Token.UNIQUE) {
|
||||
queryBlock.setDistionOption(SQLSetQuantifier.UNIQUE);
|
||||
this.lexer.nextToken();
|
||||
} else if (this.lexer.token() == Token.ALL) {
|
||||
queryBlock.setDistionOption(SQLSetQuantifier.ALL);
|
||||
this.lexer.nextToken();
|
||||
}
|
||||
|
||||
this.parseSelectList(queryBlock);
|
||||
|
||||
if (this.lexer.token() == Token.INTO) {
|
||||
this.lexer.nextToken();
|
||||
|
||||
SQLExpr expr = this.expr();
|
||||
if (this.lexer.token() != Token.COMMA) {
|
||||
queryBlock.setInto(expr);
|
||||
}
|
||||
}
|
||||
|
||||
this.parseFrom(queryBlock);
|
||||
|
||||
this.parseWhere(queryBlock);
|
||||
|
||||
this.parseGroupBy(queryBlock);
|
||||
|
||||
if (this.lexer.identifierEquals(FnvHash.Constants.WINDOW)) {
|
||||
this.parseWindow(queryBlock);
|
||||
}
|
||||
|
||||
this.parseSortBy(queryBlock);
|
||||
|
||||
this.parseFetchClause(queryBlock);
|
||||
|
||||
if (this.lexer.token() == Token.FOR) {
|
||||
this.lexer.nextToken();
|
||||
this.accept(Token.UPDATE);
|
||||
|
||||
queryBlock.setForUpdate(true);
|
||||
|
||||
if (this.lexer.identifierEquals(FnvHash.Constants.NO_WAIT) || this.lexer.identifierEquals(FnvHash.Constants.NOWAIT)) {
|
||||
this.lexer.nextToken();
|
||||
queryBlock.setNoWait(true);
|
||||
} else if (this.lexer.identifierEquals(FnvHash.Constants.WAIT)) {
|
||||
this.lexer.nextToken();
|
||||
SQLExpr waitTime = this.exprParser.primary();
|
||||
queryBlock.setWaitTime(waitTime);
|
||||
}
|
||||
}
|
||||
|
||||
return this.queryRest(queryBlock, acceptUnion);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void parseFetchClause(SQLSelectQueryBlock queryBlock) {
|
||||
|
||||
// 如果是presto,则先解析 offset 再解析limit
|
||||
if (this.lexer.identifierEquals(FnvHash.Constants.OFFSET) || this.lexer.token() == Token.OFFSET) {
|
||||
this.lexer.nextToken();
|
||||
SQLExpr offset = this.exprParser.expr();
|
||||
queryBlock.setOffset(offset);
|
||||
if (this.lexer.identifierEquals(FnvHash.Constants.ROW) || this.lexer.identifierEquals(FnvHash.Constants.ROWS)) {
|
||||
this.lexer.nextToken();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.lexer.token() == Token.LIMIT) {
|
||||
SQLLimit limit = queryBlock.getLimit();
|
||||
// 原始的limit
|
||||
SQLLimit originLimit = this.exprParser.parseLimit();
|
||||
if (limit == null) {
|
||||
limit = originLimit;
|
||||
}
|
||||
limit.setRowCount(originLimit.getRowCount());
|
||||
queryBlock.setLimit(limit);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (this.lexer.token() == Token.FETCH) {
|
||||
this.lexer.nextToken();
|
||||
if (this.lexer.token() == Token.FIRST || this.lexer.token() == Token.NEXT || this.lexer.identifierEquals(FnvHash.Constants.NEXT)) {
|
||||
this.lexer.nextToken();
|
||||
} else {
|
||||
this.acceptIdentifier("FIRST");
|
||||
}
|
||||
SQLExpr first = this.exprParser.primary();
|
||||
queryBlock.setFirst(first);
|
||||
if (this.lexer.identifierEquals(FnvHash.Constants.ROW) || this.lexer.identifierEquals(FnvHash.Constants.ROWS)) {
|
||||
this.lexer.nextToken();
|
||||
}
|
||||
|
||||
if (this.lexer.token() == Token.ONLY) {
|
||||
this.lexer.nextToken();
|
||||
} else {
|
||||
this.acceptIdentifier("ONLY");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
-1
@@ -18,7 +18,8 @@ package com.alibaba.druid.sql.dialect.presto.parser;
|
||||
import com.alibaba.druid.sql.ast.SQLExpr;
|
||||
import com.alibaba.druid.sql.ast.SQLName;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLInsertInto;
|
||||
import com.alibaba.druid.sql.dialect.phoenix.parser.PhoenixExprParser;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelect;
|
||||
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectStatement;
|
||||
import com.alibaba.druid.sql.parser.Lexer;
|
||||
import com.alibaba.druid.sql.parser.SQLStatementParser;
|
||||
import com.alibaba.druid.sql.parser.Token;
|
||||
@@ -35,6 +36,18 @@ public class PrestoStatementParser extends SQLStatementParser {
|
||||
super(new PrestoExprParser(lexer));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrestoSelectParser createSQLSelectParser() {
|
||||
return new PrestoSelectParser(this.exprParser, selectListCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PGSelectStatement parseSelect() {
|
||||
PrestoSelectParser selectParser = createSQLSelectParser();
|
||||
SQLSelect select = selectParser.select();
|
||||
return new PGSelectStatement(select);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void parseInsertColumns(SQLInsertInto insert) {
|
||||
if (lexer.token() == Token.RPAREN ) {
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.presto.visitor;
|
||||
|
||||
import com.alibaba.druid.sql.ast.SQLLimit;
|
||||
import com.alibaba.druid.sql.dialect.phoenix.visitor.PhoenixASTVisitor;
|
||||
import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor;
|
||||
|
||||
/**
|
||||
* presto 的输出的视图信息
|
||||
*
|
||||
* @author zhangcanlong
|
||||
* @since 2022-01-07
|
||||
*/
|
||||
public class PrestoOutputVisitor extends SQLASTOutputVisitor implements PhoenixASTVisitor {
|
||||
public PrestoOutputVisitor(Appendable appender) {
|
||||
super(appender);
|
||||
}
|
||||
|
||||
public PrestoOutputVisitor(Appendable appender, boolean parameterized) {
|
||||
super(appender, parameterized);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(SQLLimit x) {
|
||||
if (x.getOffset() != null) {
|
||||
this.print0(this.ucase ? " OFFSET " : " offset ");
|
||||
x.getOffset().accept(this);
|
||||
}
|
||||
this.print0(this.ucase ? " LIMIT " : " limit ");
|
||||
x.getRowCount().accept(this);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,7 @@ import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTParameterizedVisito
|
||||
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleParameterizedOutputVisitor;
|
||||
import com.alibaba.druid.sql.dialect.phoenix.visitor.PhoenixOutputVisitor;
|
||||
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGOutputVisitor;
|
||||
import com.alibaba.druid.sql.dialect.presto.visitor.PrestoOutputVisitor;
|
||||
import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerOutputVisitor;
|
||||
import com.alibaba.druid.sql.parser.SQLParserFeature;
|
||||
import com.alibaba.druid.sql.parser.SQLParserUtils;
|
||||
@@ -78,7 +79,7 @@ public class ParameterizedOutputVisitorUtils {
|
||||
return parameterize(sql, dbType, null, null);
|
||||
}
|
||||
|
||||
public static String parameterize(String sql, DbType dbType, VisitorFeature ...features) {
|
||||
public static String parameterize(String sql, DbType dbType, VisitorFeature...features) {
|
||||
return parameterize(sql, dbType, null, features);
|
||||
}
|
||||
|
||||
@@ -408,6 +409,8 @@ public class ParameterizedOutputVisitorUtils {
|
||||
return new DB2OutputVisitor(out, true);
|
||||
case phoenix:
|
||||
return new PhoenixOutputVisitor(out, true);
|
||||
case presto:
|
||||
return new PrestoOutputVisitor(out, true);
|
||||
default:
|
||||
return new SQLASTOutputVisitor(out, true);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user