You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Apache Calcite中验证单独表达式?遇列未找到问题求助

问题解决:Apache Calcite单独验证条件表达式时列找不到的异常

问题原因

验证完整SQL查询时,parseQuery()解析出的SqlSelect包含FROM子句,Calcite的SqlValidator会自动从FROM子句中获取表的行类型作为WHERE子句的验证上下文;而验证孤立条件表达式时,parseExpression()仅得到独立的表达式节点(如SqlBinaryOp),Validator没有默认上下文来识别列名,因此抛出Column 'a' not found in any table异常。

解决方案

手动为SqlValidator指定验证上下文,明确表达式基于目标表的行类型进行验证。具体实现步骤如下:

  1. 在初始化阶段获取目标表的Calcite表条目,创建对应的SqlValidatorNamespace
  2. 从SqlValidatorNamespace中提取表的SqlValidatorScope作为验证上下文
  3. 调用带范围参数的validate方法,传入表达式和上下文完成验证

修改后的代码

ConditionValidator类

public class ConditionValidator {
    private final String sql;
    private final SchemaPlus rootSchema;
    private final FrameworkConfig frameworkConfig;
    private final RelDataTypeFactory relDataTypeFactory;
    private final CalciteCatalogReader catalogReader;
    private final SqlOperatorTable sqlOperatorTable;
    private final SqlValidator validator;
    private final SqlValidatorScope tableScope; // 目标表的验证范围

    public ConditionValidator(String sql) {
        this.sql = sql;
        SchemaPlus rootSchema = Frameworks.createRootSchema(true);
        DummyTable testTable = new DummyTable("test_table");
        rootSchema.add(testTable.getTableName(), testTable);
        this.rootSchema = rootSchema;

        this.frameworkConfig = Frameworks.newConfigBuilder()
                .parserConfig(SqlParser.config()
                        .withLex(Lex.MYSQL)
                        .withConformance(SqlConformanceEnum.DEFAULT))
                .defaultSchema(rootSchema)
                .operatorTable(SqlStdOperatorTable.instance())
                .build();

        this.relDataTypeFactory = new SqlTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
        Properties properties = new Properties();
        properties.setProperty(CalciteConnectionProperty.CASE_SENSITIVE.camelName(), "true");
        this.catalogReader = new CalciteCatalogReader(
                CalciteSchema.from(rootSchema),
                CalciteSchema.from(rootSchema).path(rootSchema.getName()),
                relDataTypeFactory,
                new CalciteConnectionConfigImpl(properties));

        this.sqlOperatorTable = SqlOperatorTables.chain(frameworkConfig.getOperatorTable(), catalogReader);
        this.validator = SqlValidatorUtil.newValidator(sqlOperatorTable, catalogReader, relDataTypeFactory, frameworkConfig.getSqlValidatorConfig());

        // 初始化目标表的验证范围
        CalciteSchema schema = CalciteSchema.from(rootSchema);
        CalciteSchema.TableEntry tableEntry = schema.getTable(testTable.getTableName(), true);
        SqlValidatorNamespace tableNamespace = validator.createNamespace(tableEntry, null);
        tableNamespace.validate();
        this.tableScope = validator.getNamespaceScope(tableNamespace);
    }

    public SqlNode validate() {
        SqlParser sqlParser = SqlParser.create(sql, frameworkConfig.getParserConfig());
        SqlNode sqlNode;
        try {
            sqlNode = sqlParser.parseExpression();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        // 传入表的验证范围,让Validator识别表达式中的列
        return validator.validate(sqlNode, tableScope);
    }
}

DummyTable类(保持不变)

public class DummyTable extends AbstractTable {
    private final String tableName;
    public DummyTable(String tableName) {
        this.tableName = tableName;
    }
    @Override
    public RelDataType getRowType(RelDataTypeFactory typeFactory) {
        RelDataTypeFactory.Builder builder = typeFactory.builder();
        builder.add("a", SqlTypeName.BIGINT);
        builder.add("b", SqlTypeName.BIGINT);
        return builder.build();
    }
    public String getTableName() {
        return tableName;
    }
}

代码说明

  • 新增tableScope字段存储目标表的验证上下文,确保Validator知道表达式中的列来自哪个表
  • 在构造函数中通过CalciteSchema获取表条目,创建并验证SqlValidatorNamespace,进而得到对应的验证范围
  • 验证表达式时调用validator.validate(sqlNode, tableScope),传入上下文后Validator即可正确识别列名并验证表达式合法性

内容的提问来源于stack exchange,提问作者Kyabia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 03:05:12