Apache Calcite——新增DDL语法支持

本文介绍了在Calcite中扩展DDL语法的过程,重点讲解了如何新增dropmaskfunction语法的解析与执行逻辑,并提供了详细的实现步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在日常需求中,需要Calcite中添加对DDL语法的支持,这里记录一下调研过程以及实施结果。

parser.jj、parserImpls.ftl和config.fmpp

其中core模块中的parser.jj中定义了支持的语法模板,core模块中的parserImpls.ftl为空,在Server模块中的parserImpls.ftl中定义了具体的DDL语法,作为对core模块中的parserr.jj的补充,即如果采用serser模块中编译生成的SqlDdlParserImpl,是可以解析dql与ddl的,如果只是用core模块编译生成的SqlParserImpl则只能支持dql。

新增drop mask function语法解析

1:在parserImpls.ftl中新增

SqlDrop SqlDropMaskFunction(Span s, boolean replace) :
{
    final boolean ifExists;
    final SqlIdentifier id;
}
{
    <MASK> <FUNCTION> ifExists = IfExistsOpt()
    id = CompoundIdentifier() {
        return SqlDdlNodes.dropMaskFunction(s.end(this), ifExists, id);
    }
}

上述的 就对应的Sql语句里面的Mask Function

drop mask function if exists "my udf"

其中 ifExists = IfExistsOpt()是判断语句中是否包含if exists,如果是则ifExists 为true,最终会作为参数调用SqlDdlNodes.dropMaskFunction这个方法。而在SqlDdlNodes中,定义了Calcite当前支持的所有Ddl语法,当前具体包括:
DDL
其实这个类更像是工厂类,根据不同的方法去实例化不通的操作对象。

具体dropMaskFunction:

  /**
   * Create a drop mask function
   */
  public static SqlDrop dropMaskFunction(SqlParserPos pos,
      boolean ifExists, SqlIdentifier name) {
    return new SqlDropMaskFunction(pos, ifExists, name);
  }

SqlNode是Calcite中解析Sql后得到的抽象语法树的组成元素,因此我们需要新增相应的SqlNode对应新增的语句:
在这里插入图片描述

public class SqlDropMaskFunction extends SqlDropObject {
  // SqlKind.DROP_MASK_FUNCTION 新增
  private static final SqlOperator OPERATOR =
      new SqlSpecialOperator("DROP MASK FUNCTION", SqlKind.DROP_MASK_FUNCTION);
  /**
   * Creates a SqlDropFunction.
   *
   * @param pos   当前Sql的行数以及开始和结束位置
   * @param ifExists  是否已经存在
   * @param name 函数名
   */
  public SqlDropMaskFunction(SqlParserPos pos, boolean ifExists, SqlIdentifier name) {
    super(OPERATOR ,pos, ifExists, name);
  }
}

2:在config.fmpp中新增

在这里插入图片描述
再根据需要添加保留关键字即可。

到这里其实解析已经可以过了。可以在ServerParserTest中添加:

3:测试

    final String sql = "drop mask function if exists \"my udf\"";
    final String expected = "DROP MASK FUNCTION IF EXISTS `my udf`";
    sql(sql).ok(expected);

进行相应测试。

新增drop mask function语法执行

上述只是新增了drop mask function语法支持,具体要具有执行能力的话,还需添加具体的执行能力,我们知道在使用JDBC执行Sql语句时,通过statement的execute方法,因此我们从AvaticaStatement的execute的方法入手,去查找具体DDL的执行逻辑:

  // AvaticaStatement
  public boolean execute(String sql) throws SQLException {
    checkOpen();
    checkNotPreparedOrCallable("execute(String)");
    // 执行具体的Sql
    executeInternal(sql);
    // Result set is null for DML or DDL.
    // Result set is closed if user cancelled the query.
    return openResultSet != null && !openResultSet.isClosed();
  }

在继续查看executeInternal方法,其中重复调用了connection的prepareAndExecuteInternal方法:

          Meta.ExecuteResult x =
              connection.prepareAndExecuteInternal(this, sql, maxRowCount1);

继续查看可以看到最终调用了CalcitePrepareImpl中的prepare2_:

      if (sqlNode.getKind().belongsTo(SqlKind.DDL)) {
        executeDdl(context, sqlNode);

        return new CalciteSignature<>(query.sql,
            ImmutableList.of(),
            ImmutableMap.of(), null,
            ImmutableList.of(), Meta.CursorFactory.OBJECT,
            null, ImmutableList.of(), -1, null,
            Meta.StatementType.OTHER_DDL);
      }

上述判断当前语法是否是DDL,如果是直接执行executeDdl方法
首先需要将新增的SqlKind.DROP_MASK_FUNCTION新增为SqlKind.DDL中:
在这里插入图片描述

执行的具体方法如下:

  @Override public void executeDdl(Context context, SqlNode node) {
    final CalciteConnectionConfig config = context.config();
    final SqlParserImplFactory parserFactory =
        config.parserFactory(SqlParserImplFactory.class, SqlParserImpl.FACTORY);
    final DdlExecutor ddlExecutor = parserFactory.getDdlExecutor();
    ddlExecutor.executeDdl(context, node);
  }

其中默认的ddlExecutor实现是ServerDdlExecutor,其中定义了根据不同SqlNode参数调用的方法:
在这里插入图片描述
可以看出具体的执行逻辑,我们新增的drop mask func在SqlDropObject中,其中根据枚举不同的ddl类型执行不同的操作,是否需要新增drop mask func的类型,就由用户自行决定 。
实现Demo如下:

case DROP_FUNCTION:
      existed = schemaExists && schema.removeFunction(objectName);
      if (!existed && !drop.ifExists) {
        throw SqlUtil.newContextException(drop.name.getParserPosition(),
            RESOURCE.functionNotFound(objectName));
      }
      break;
    case DROP_MASK_FUNCTION:
      System.out.println("Drop Mask Function Execute");
      break;
    case OTHER_DDL:
    default:
      throw new AssertionError(drop.getKind());

直接运行可以看到具体的内容输出。

Apache Calcite 是一个开源的 SQL 解析器、优化器、执行器和 JDBC 驱动程序。它支持多种数据源,包括关系型数据库、NoSQL 数据库、文件系统和流数据。以下是 Apache Calcite 的一些语法介绍: 1. SELECT 语句:用于从表中检索数据。语法如下: SELECT [DISTINCT] column1, column2, ... FROM table_name WHERE condition; 2. INSERT 语句:用于向表中插入新数据。语法如下: INSERT INTO table_name (column1, column2, ...) VALUES (value1, value2, ...); 3. UPDATE 语句:用于更新表中的数据。语法如下: UPDATE table_name SET column1 = value1, column2 = value2, ... WHERE condition; 4. DELETE 语句:用于从表中删除数据。语法如下: DELETE FROM table_name WHERE condition; 5. JOIN 语句:用于将两个或多个表中的数据组合在一起。语法如下: SELECT column1, column2, ... FROM table1 INNER JOIN table2 ON table1.column = table2.column; 6. UNION 语句:用于将两个或多个 SELECT 语句的结果集合并在一起。语法如下: SELECT column1, column2, ... FROM table1 UNION SELECT column1, column2, ... FROM table2; 7. GROUP BY 语句:用于将结果集按照指定列进行分组。语法如下: SELECT column1, column2, ... FROM table_name GROUP BY column1, column2, ...; 8. HAVING 语句:用于对 GROUP BY 子句返回的结果进行筛选。语法如下: SELECT column1, column2, ... FROM table_name GROUP BY column1, column2, ... HAVING condition; 9. ORDER BY 语句:用于按照指定列对结果集进行排序。语法如下: SELECT column1, column2, ... FROM table_name ORDER BY column1 ASC/DESC, column2 ASC/DESC, ...; 以上是 Apache Calcite 的一些常用语法介绍。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NobiGo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值