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