我正在实现一个简单的应用程序,它可以在SQL语句中更改列名称(并且只保留表名)。该语句作为String
传递,修改后的语句也作为String
返回,不涉及数据库连接。apache方解石区分表名称的列名称
为了达到这个目的,我使用了Apache Calcite的SQL解析器。我将SQL字符串解析为SqlNode
,接受SqlVisitor
创建重命名为SqlNode
,然后将所有内容写回到String
(使用SqlNode.toSqlString()
)。
问题是我不知道如何区分解析的SqlNode
对象中的列和表之间的区别,同时接受SqlVisitor
。两者都表示为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
是一列或表?
SqlScopedShuttle呢? –
SqlScopedShuttle听起来很有用,但它不会像你想要的那么多。当你递归到树中时,它只保留一堆AST节点(SqlNode)。它并不知道SQL范围规则的任何内容。 –