1

我正在尝试使用 JSqlParser 在 SQL 查询中查找 SQL 对象(令牌?)的位置(行就足够了)。

例如,在查询中:

SELECT a
FROM table
WHERE a = 1 AND
      b = 2 AND
      c = 3

在查看表达式 b = 2 时,我想知道它在第 4 行。或者,当查看 SelectItem "a" 时,我想知道它在第 1 行。

没有在文档中看到任何关于它们位置的内容,也没有在对象本身中看到任何内容。如果目前无法做到这一点,您能否建议一种我自己添加此功能的好方法(就性能而言最简单和最快)。

4

1 回答 1

1

如果没有 JSqlParser 的修补版本,则不能。目前,JSqlParser V1.2-SNAPSHOT 确实为您提供了一些特定已解析令牌的 AST - 节点信息,但并非全部。使用以下代码截断:

public static void main(String[] args) throws JSQLParserException {
    String sql = "SELECT a\n"
            + "FROM table\n"
            + "WHERE a = 1 AND\n"
            + "      b = 2 AND\n"
            + "      c = 3";

    SimpleNode node = (SimpleNode) CCJSqlParserUtil.parseAST(sql);

    node.jjtAccept(new CCJSqlParserDefaultVisitor() {
        @Override
        public Object visit(SimpleNode node, Object data) {
            System.out.println(node.toString() + " firstToken=" + node.jjtGetFirstToken().image 
                    + " line=" + node.jjtGetFirstToken().beginLine);
            return super.visit(node, data);
        }
    }, null);
}

您可以获得有关所有已保存 AST 节点的信息。探索 SimpleNode 的界面,您还可以了解令牌在源 sql 字符串中的绝对位置和范围。

这种“限制”来自 JSqlParsers 功能驱动的开发以及对生成所有 AST 节点的巨大性能影响。此外,一些 AST 节点与 JSQlParsers 解析对象(如ColumnTable等)链接,这不是使用 JavaCC 自动完成的,而是必须在语法定义中完成。

起初我提到了一个修补过的 JSqlParser。这确实很容易通过修改pom.xml和设置

<nodeDefaultVoid>true</nodeDefaultVoid>

。然后为所有产品生成 AST 节点。但是您会看到,即使对于您的简单语句,它也会生成一棵巨大的树。

如果您需要此信息用于某些特定产品(例如EqualTo对象),可以通过 JSqlParser (github) 的功能请求来集成。

为什么是那两种树?

JSqlParser 中的解析树和抽象语法树是有区别的。对于从ASTNodeAccessImpl扩展的对象,这两者之间存在联系。交付的解析树对象是分析 sql 部分的更实用的方法。例如,您可以将Table对象设置为Column对象以引用该表中的列。使用 AST 方法,这将导致构建更多节点来构建点、标识符等。

AST 节点具有您需要的信息,即令牌在原始 sql 文本中的确切位置。如果您查看Function对象,您可以使用方法getASTNode来获取相应的 AST - 节点以获取 sql 中的确切位置。但正如我所写,这仅适用于少数解析树对象。如果您需要特定的节点来获取此信息,我将很乐意为其扩展 JSqlParser,但请记住,获取所有这些节点会对性能和内存产生巨大影响。

于 2017-10-01T10:06:06.723 回答