Presto新增一个sql语法的实现流程

        虽然presto是基于标准的sql语法进行开发使用,但是在实际使用中,有时候标准的sql不一定能满足的了各个业务场景的需要,需要做一些定制化的sql语法增强或者修改等。 本文假设以实现一个刷新缓存的命令refresh cache作为样例探索如何进行presto的sql语法的适配开发。

  1.      首先需要适配SqlBase.g4的语法树关键词声明:

         sqlBase.g4中声明关键词:

    .....
    | VACUUM TABLE qualifiedName (FULL (UNIFY)?)? (PARTITION partition=string)?
        (AND_WAIT)?                                                    #vacuumTable
    | REFRESH CACHE                                       #refreshCache
    ;

      antlr4会根据#后后边的字符串生成的对应的StatementContext类,比如这里是RefreshCacheContext

    2. 编译presto-parser模块,得到vist方法名

     编译presto-parser后,antlr4会自动根据sqlBase.g4文件生产对应的语法树处理源码,在

SqlBaseBaseVisitor.java中可以找到对应的方法名:
    ...
	@Override public T visitRefreshCache(SqlBaseParser.RefreshCacheContext ctx) { return visitChildren(ctx); }
    ....

3.  AstBuilder.java 中复写SqlBaseBaseVisitor.java的默认实现

    ...
    @Override
    public Node visitRefreshCache(SqlBaseParser.RefreshCacheContext ctx)
    {
        return new RefreshCache();
    }
    ...

4.  实现语法树的Statement

public class RefreshCache
        extends Statement
{
    public RefreshCache()
    {
        super(Optional.empty());
    }

    @Override
    public List<? extends Node> getChildren()
    {
        return ImmutableList.of();
    }

    @Override
    public int hashCode()
    {
        return Objects.hash(this);
    }

    @Override
    public boolean equals(Object obj)
    {
        return true;
    }

    @Override
    public String toString()
    {
        return null;
    }

    @Override
    public <R, C> R accept(AstVisitor<R, C> visitor, C context)
    {
        return visitor.visitRefreshCache(this, context);
    }
}

    可以在Node的statement中存储一些信息传递到后边的execute阶段使用。

   5. AstVisitor.java实现visit的处理

  我们实现的node是statememt,因此直接visitStatement即可

    ....
    protected R visitRefreshCache(RefreshCache node, C context)
    {
        return visitStatement(node, context);
    }
    ....

   6. StatementAnalyzer.java的Visitor类中覆盖实现

   ...
    @Override
    protected Scope visitRefreshCache(RefreshCache node, Optional<Scope> scope)
    {
        return createAndAssignScope(node, scope);
    }
    ....

   7. StatementUtils.java中归类此语法为DDL,避免Presto绑定到SqlQueryExecution中

...
builder.put(RefreshCache.class, QueryType.DATA_DEFINITION);
...

    8. CoordinatorModule.java中绑定statement与task的实现

    ...
    bindDataDefinitionTask(binder, executionBinder, RefreshCache.class, RefreshMetaStoreTask.class);
    ...

    9. 实现真正的Task行为:

public class RefreshMetaStoreTask
        implements DataDefinitionTask<RefreshCache>
{
    private static final Logger log = Logger.get(RefreshMetaStoreTask.class);

    @Override
    public String getName()
    {
        return "Refresh MetaStore";
    }

    @Override
    public ListenableFuture<?> execute(RefreshCache statement, TransactionManager transactionManager, Metadata metadata, AccessControl accessControl, QueryStateMachine stateMachine, List<Expression> parameters, HeuristicIndexerManager heuristicIndexerManager)
    {
        log.info("refresh the metastore cache finish");
        return immediateFuture(null);
    }
}

      到此,一个新的sql语法便完成适配。

对新语法进行测试:

1. 在presto的客户端输入refresh cache:

2. 可以从日志中看到task已经被执行:

 


版权声明:本文为wangfeihuo原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。