I'm implementing a simple app that changes column names (and leaves table names alone) in SQL statements. The statement is passed as a String
, and modified one is also returned as a String
, there's no database connection involved.
To achieve this, I'm using Apache Calcite's SQL parser. I parse the SQL string to the SqlNode
, accept a SqlVisitor
that creates renamed SqlNode
, and then write everything back to String
(using SqlNode.toSqlString()
).
The problem is that I don't know how to tell the difference between columns and tables in parsed SqlNode
object while accepting a SqlVisitor
. Both are represented as SqlIdentifier
, having the same SqlKind
. Hence, when SqlVisitor
is visiting the SqlIdentifier
, it will rename it whether it's a column or a table.
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();
}
for example
SELECT name, address, age FROM mytablename WHERE age = 23 AND name = 'John'
will be modified into
SELECT `name-test`, `address-test`, `age-test` FROM `mytablename-test` WHERE `age-test` = 23 AND `name-test` = 'John'
How could I tell if given SqlIdentifier
is a column or a table ?