Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java apache方解石可区分列名和表名_Java_Sql_Parsing_Apache Calcite - Fatal编程技术网

Java apache方解石可区分列名和表名

Java apache方解石可区分列名和表名,java,sql,parsing,apache-calcite,Java,Sql,Parsing,Apache Calcite,我正在实现一个简单的应用程序,它可以更改SQL语句中的列名(并且不使用表名)。语句作为字符串传递,修改后的语句也作为字符串返回,不涉及数据库连接 为了实现这一点,我使用ApacheCalcite的SQL解析器。我将SQL字符串解析为SqlNode,接受创建重命名的SqlNode的SqlVisitor,然后将所有内容写回string(使用SqlNode.toSqlString()) 问题是,在接受SqlVisitor时,我不知道如何区分解析的SqlNode对象中的列和表之间的差异。两者都表示为Sq

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

为了实现这一点,我使用ApacheCalcite的SQL解析器。我将SQL字符串解析为
SqlNode
,接受创建重命名的
SqlNode
SqlVisitor
,然后将所有内容写回
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
sqlParser
。下面发布的一些片段

  public void convertSelect(SqlSelect root) {
    convertFrom(root.getFrom());
    convertWhere(root.getWhere());
  }

  public void convertFrom(SqlNode from) {
    if (from instanceof SqlJoin) {
      convertFromOfJoinExpression((SqlJoin)from);
    }
  }

  public String extractTableFromJoinNode(SqlNode jnn) {
    if (jnn instanceof SqlBasicCall) {
      SqlBasicCall asExp = (SqlBasicCall)jnn;
      if (asExp.getKind().equals(SqlKind.AS)) {
        extractTableFromJoinNodeAsExpression(asExp);
      }
    }
    return "SomeTableAlias";
  }
通常,您将在
from
语句中获得
表。您将在
select
语句中获得


最后但并非最不重要的是,
calcite
专门通过应用大量优化规则来优化查询。根据需要(转换列/表名),
calcite
可能不是最佳选择

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

验证器中的两个关键概念是作用域(
SqlValidatorScope
)和名称空间(
SqlValidatorNamespace

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

名称空间看起来像一个表,并且有一个列列表。它可能是一个表,也可能是FROM子句中的一个子查询。如果您在作用域中,可以查找表别名,获取名称空间,然后查看它有哪些列


出于您的目的,如果有一个
SqlShuttle
的变体,它确切地知道您在哪个范围内,并且您可以在哪里要求将标识符扩展到表和列引用中,这将非常有用。不幸的是,还没有人构建这样的东西。

SQLScopedShattle呢?SQLScopedShattle听起来很有用,但它的作用并没有你想要的那么多。当您递归到树中时,它只保留一堆AST节点(SqlNode)。它对SQL作用域规则一无所知。@PiotrŚmietana如果你最终得到了一些工作代码,你能分享一下吗?@Arvidaa我想我使用了一些断断续续的解决方法。我不记得它到底是什么,也没有访问此代码的权限,所以我无法提供任何详细信息。