我正在尝试使用presto-parser。我需要知道的是如何分析和提取我们创建的Statement
:
SqlParser SQL_PARSER = new SqlParser();
Statement statement = SQL_PARSER.createStatement(query);
似乎没有任何方法可以从Statement
getters / setters中获得。我调试了Statement对象,我可以从调试视图中看到我需要获取的值。
请参阅:
我需要获取由SqlParser提取的select,from,where,groupBy,orderBy和limit值。
答案 0 :(得分:5)
从sql字符串中,您可以通过强制转换Query
来获取Statement
(扩展Statement)。 Query.getQueryBody
会返回QueryBody
,您可以将其转换为QuerySpecification
(扩展QueryBody
)。从QuerySpecification
开始,您现在可以获得您正在寻找的内容。这是一个简单的例子:
public class PrestoParserTest {
public static void main(String[] args) {
SqlParser parser = new SqlParser();
String sql = "select * from xyz where x=y group by x order by y limit 10";
Query query = (Query)parser.createStatement(sql);
QuerySpecification body = (QuerySpecification)query.getQueryBody();
Select select = body.getSelect();
System.out.println("Columns = " + select.getSelectItems());
System.out.println("From = " + body.getFrom().get());
Optional<Expression> where = body.getWhere();
System.out.println("Where = " + where.get());
System.out.println("Group by = " + body.getGroupBy());
System.out.println("Order by = " + body.getOrderBy());
System.out.println("Limit = " + body.getLimit().get());
}
}
运行此命令返回:
Columns = [*]
From = Table{xyz}
Where = ("x" = "y")
Group by = ["x"]
Order by = [SortItem{sortKey="y", ordering=ASCENDING, nullOrdering=UNDEFINED}]
Limit = 10
答案 1 :(得分:1)
虽然给出的答案有效,但它需要在运行时进行大量类型检查和转换,这很容易出错。 (特别是如果您具有包含许多联接和子表达式的高度嵌套的查询)
相反,Presto的查询解析器提供了一个基础AstVisitor
抽象类,您可以将其作为子类,它将为您处理所有强制转换和分派。
例如,要获取查询中使用的所有表的列表(在scala中,但适用于Java):
class VisitSourceTables extends AstVisitor[List[String], List[String]]{
override def visitTable(node: Table, context: List[String]): List[String] = {
List[String](
node.getName.toString
)
}
override def visitJoin(node: Join, context: List[String]): List[String] = {
process(node.getLeft, context) ++ process(node.getRight, context)
}
(one method per type of thing to visit)
...
}
这是一个示例访问者,它没有做任何有用的事情,但是可以正确地遍历查询树。我发现弄清楚如何编写自己的代码非常有用: https://github.com/prestodb/presto/blob/master/presto-parser/src/main/java/com/facebook/presto/sql/tree/DefaultTraversalVisitor.java
答案 2 :(得分:0)
问题有两个部分
以下是可扩展的解决方案:
class DepthFirstVisitor<R, C> extends AstVisitor<Stream<R>, C> {
private final AstVisitor<R, C> visitor;
public DepthFirstVisitor(AstVisitor<R, C> visitor) {
this.visitor = visitor;
}
public static <R, C> DepthFirstVisitor<R, C> by(AstVisitor<R, C> visitor) {
return new DepthFirstVisitor<>(visitor);
}
@Override
public final Stream<R> visitNode(Node node, C context) {
Stream<R> nodeResult = Stream.of(visitor.process(node, context));
Stream<R> childrenResult = node.getChildren().stream()
.flatMap(child -> process(child, context));
return Stream.concat(nodeResult, childrenResult)
.filter(Objects::nonNull);
}
}
class Extractors {
public static AstVisitor<Table, Object> extractTables() {
return new AstVisitor<Table, Object>() {
@Override
protected Table visitTable(Table node, Object context) {
return node;
}
};
}
}
// Thats it folks
DepthFirstVisitor<Table, ?> depthFirstVisitor = DepthFirstVisitor.by(Extractors.extractTables());
String sql = "select * from foo tablesample system (10) join bar tablesample bernoulli (30) on not(a.id > b.id)";
Statement statement = new SqlParser().createStatement(sql, new ParsingOptions());
List<Table> tables = statement.accept(depthFirstVisitor, null)
.collect(Collectors.toList());
System.out.println(tables);
这可以在不进行丑陋的类型检查的情况下完成。
打印[Table{foo}, Table{bar}]