java - apache calcite 区分列名和表名

标签 java sql parsing apache-calcite

我正在实现一个简单的应用程序,它可以更改 SQL 语句中的列名称(并保留表名称)。该语句作为 String 传递,修改后的语句也作为 String 返回,不涉及数据库连接。

为了实现这一点,我使用 Apache Calcite 的 SQL 解析器。我将 SQL 字符串解析到 SqlNode,接受创建重命名的 SqlNodeSqlVisitor,然后将所有内容写回 String(使用SqlNode.toSqlString())。

问题是我不知道在接受 SqlVisitor 时如何区分解析的 SqlNode 对象中的列和表之间的区别。两者都表示为 SqlIdentifier,具有相同的 SqlKind。因此,当SqlVisitor访问SqlIdentifier时,它会重命名它,无论它是列还是表。

private String changeNames(String str) throws SqlParseException {
    SqlShuttle visitor = new SqlShuttle() {
        private String rename(String str) {
            return str + "-test";
        }

        @Override
        public SqlNode visit(SqlIdentifier identifier) {
            SqlIdentifier output = new SqlIdentifier(rename(identifier.getSimple()), identifier.getCollation(), identifier.getParserPosition());
            return output;
        }
    };

    SqlParser.ConfigBuilder configBuilder =  SqlParser.configBuilder();
    configBuilder.setLex(Lex.MYSQL);
    SqlParser.Config config = configBuilder.build();

    SqlParser parser = SqlParser.create(str, config);
    SqlNode parsedStatement = parser.parseQuery(str);
    SqlNode outputNode = parsedStatement.accept(visitor);

    return outputNode.toSqlString(SqlDialect.DUMMY).getSql();
}

例如

SELECT name, address, age FROM mytablename WHERE age = 23 AND name = 'John'

将修改为

SELECT `name-test`, `address-test`, `age-test` FROM `mytablename-test` WHERE `age-test` = 23 AND `name-test` = 'John'

如何判断给定的 SqlIdentifier 是列还是表?

最佳答案

要解析表和列的标识符并确定它们的类型,您需要使用 Calcite 的 validator (SqlValidator)。 validator 理解 SQL 名称解析规则(例如,FROM 子句中的别名是否可以在子查询中看到),而我们故意不让解析器及其生成的 SqlNode 数据结构了解诸如此类的事情。

validator 中的两个关键概念是范围 (SqlValidatorScope) 和命名空间 (SqlValidatorNamespace)。

范围是您所处的位置并尝试解析标识符。例如,您可能位于查询的 SELECT 子句中。或者在特定子查询的 WHERE 子句中。您将能够在不同范围内看到不同的表和列集合。即使 GROUP BY 子句和 ORDER BY 子句也有不同的范围。

命名空间看起来像一个表,并且有一个列列表。它可能是一个表,或者 FROM 子句中的子查询。如果您在某个范围内,则可以查找表别名,获取命名空间,然后查看它有哪些列。

出于您的目的,如果有一个 SqlShuttle 的变体能够准确地知道您所在的范围,以及您可以在哪里要求将标识符扩展到表和列引用,那么将会很有用。不幸的是还没有人 build 出这样的东西。

关于java - apache calcite 区分列名和表名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37288184/

相关文章:

java - 使网络密集型代码更加健壮

mysql - 如何将列名与其他参数一起传递

sql - 如何在 linux shell 上的 sql 查询中使用 "%"字符?

java - html解析器的问题

java - native map 未显示在代号为 1 的 Android 设备的分层布局中

Java,获取核心转储

java.time : How to validate calendar weeks

javascript - 如果数据 = 0,则不更新(执行)表。 (JavaScript/SQL)

ruby - 如何从 ruby​​ 中的 url 获取网站名称?

java - 正在解析HH :mm (with two digits minute) to LocalTime with JodaTime