如何在没有架构信息的情况下从 RelBuild 构建 sql?

how to build sql from RelBuild without schema info?

我想生成 sql 使用方解石。像这样

org.apache.calcite.rel.rel2sql.RelToSqlConverterTest#testAntiJoin

final FrameworkConfig frameworkConfig = Frameworks.newConfigBuilder()
       .parserConfig(SqlParser.Config.DEFAULT)
//       .defaultSchema(schema)
       .build();

final RelBuilder builder = RelBuilder.create(frameworkConfig);

final RelBuilder builder = relBuilder();
final RelNode root = builder
       .scan("DEPT")
        .scan("EMP")
        .join(
            JoinRelType.ANTI, builder.equals(
              builder.field(2, 1, "DEPTNO"),
              builder.field(2, 0, "DEPTNO")))
        .project(builder.field("DEPTNO"))
        .build();

但如果我不设置架构,将抛出 table 未找到的异常。 有什么方法可以在没有架构信息的情况下生成 sql。

目标是生成 sql。只生成 sql.



回复第一个答案。因为评论字符长度限制。

我的场景是商业智能。 DataSource可以有很多,比如Hive、ClickHouse等等。而且还有很多table。我还需要动态删除或添加数据源。所以我认为让 Calcite 了解所有数据源是不合适的。我还有两个问题:

  1. 如何创建 'free-standing' table 对象
  2. 检查是否可以使用 SqlNode 来执行此操作。例如:
        SqlIdentifier from = new SqlIdentifier("testTable", SqlParserPos.QUOTED_ZERO);
        SqlNode[] nodes = new SqlNode[2];
        nodes[0] = new SqlIdentifier("a", SqlParserPos.QUOTED_ZERO);
        nodes[1] = SqlLiteral.createExactNumeric("1", SqlParserPos.QUOTED_ZERO);
        SqlNode where = new SqlBasicCall(SqlStdOperatorTable.EQUALS, nodes, SqlParserPos.QUOTED_ZERO);
        SqlIdentifier selectNode = new SqlIdentifier("a", SqlParserPos.QUOTED_ZERO);
        SqlSelect select = new SqlSelect(SqlParserPos.QUOTED_ZERO, SqlNodeList.EMPTY,
                new SqlNodeList(Arrays.asList(selectNode), SqlParserPos.QUOTED_ZERO),
                from,
                where,
                null,
                null,
                null,
                null,
                null,
                null,
                null);
        SqlString sqlString = select.toSqlString(CalciteSqlDialect.DEFAULT);
        System.out.println(sqlString.getSql());

RelBuilder 中只有一种方法使用 RelOptSchemascan(String...)(及其变体 Scan(Iterable<String>))。当您认为 RelOptSchema 的目的是作为目录服务,转换 table 名称(或 table 路径,由符合目录的 table 名称组成时,这是有道理的and/or 模式名称)转换为 RelOptTable 对象。

如果您有 'free-standing' table 对象无法通过命名空间访问,那么您可以直接创建 TableScan 关系表达式,然后调用 RelBuilder.push(RelNode) 将它们添加到堆栈。由于您从不调用 RelBuilder.scan,因此您可以使用 null RelOptSchema.

创建 RelBuilder

但在您的情况下,您似乎没有独立的 table 对象。这对 Calcite 来说是个问题,因为它需要知道您的“EMP”table 有一个名为“DEPTNO”的字段并且它的类型为 INTEGER.

所以我建议您创建一个 'virtual' 模式,其中包含类型信息但不一定由真实的 table 支持。 MockCatalogReader class,在 Calcite 的几个测试中使用,是一个很好的例子。