使用Facebook presto-parser

时间:2015-04-04 18:08:06

标签: java facebook parsing

我正在尝试使用presto-parser。我需要知道的是如何分析和提取我们创建的Statement

的查询主体
SqlParser SQL_PARSER = new SqlParser();
Statement statement = SQL_PARSER.createStatement(query);

似乎没有任何方法可以从Statement getters / setters中获得。我调试了Statement对象,我可以从调试视图中看到我需要获取的值。

请参阅:

enter image description here

我需要获取由SqlParser提取的select,from,where,groupBy,orderBy和limit值。

3 个答案:

答案 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抽象类,您可以将其作为子类,它将为您处理所有强制转换和分派。

https://github.com/prestodb/presto/blob/master/presto-parser/src/main/java/com/facebook/presto/sql/tree/AstVisitor.java

例如,要获取查询中使用的所有表的列表(在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)

问题有两个部分

  1. 访问整个AST(可以递归访问)
  2. 在每个节点上执行操作(在这种情况下,请找到表节点)

以下是可扩展的解决方案:

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}]