针对一个这样的语句,
String sql = "select id,name from users where id <5";
我们的validate 过程如下:
调用validate 方法 ,输入是一个SqlNode ,输出也是一个经过校验的SqlNode
public SqlNode validate(SqlNode topNode) {
SqlValidatorScope scope = new EmptyScope(this); //直接new 出一个EmptyScope ,
scope = new CatalogScope(scope, ImmutableList.of("CATALOG")); // CATALOG的parent 是Empty
final SqlNode topNode2 = validateScopedExpression(topNode, scope); // 将最外层的SqlNode和catalogScope 传入调用具体的validate方法
final RelDataType type = getValidatedNodeType(topNode2);
Util.discard(type);
return topNode2;
}
具体看validateScopedExpression 这个方法在做什么。方法相对简洁,仍然是一个入口的身份。 这个方法其实就是把topNode 传入进行一个注册的过程。
private SqlNode validateScopedExpression(
SqlNode topNode,
SqlValidatorScope scope) {
SqlNode outermostNode = performUnconditionalRewrites(topNode, false); //todo
cursorSet.add(outermostNode);
top = outermostNode;
TRACER.trace("After unconditional rewrite: {}", outermostNode);
if (outermostNode.isA(SqlKind.TOP_LEVEL)) {
//isA 是当前对象的一个方法,入参是一个set ,判断当前对象是否是的set 中的一员
registerQuery(scope, null, outermostNode, outermostNode, null, false);
// 重点方法就是这个registerQuery ,传入了上文说的catalogScope 和 最外层的SqlNode
// 针对当前的例子来说最外层的SqlNode就是这个SqlSelect
}
outermostNode.validate(this, scope);
if (!outermostNode.isA(SqlKind.TOP_LEVEL)) {
// force type derivation so that we can provide it to the
// caller later without needing the scope
deriveType(scope, outermostNode);
}
TRACER.trace("After validation: {}", outermostNode);
return outermostNode;
}
到具体的registerQuery有方法会非常的细, 根据传入的topNode 会走不同的分支,此处具体以当前的例子来往下看。
当我们看sqlToRel 的时候有非常多的 scope && nameSpace 的概念,之所以会有各种SelectNamespace ,JoinNamespace ,SelectScope ,CatalogScope 其实可以在这个方法里面看到, 基本都是在validate过程中塞进去的。
在SqlValidatorImpl 里面维护了很多的map .
protected final Map<SqlNode, SqlValidatorScope> scopes = new IdentityHashMap<>();
private final Map<SqlSelect, SqlValidatorScope> whereScopes = new IdentityHashMap<>();
private final Map<SqlSelect, SqlValidatorScope> groupByScopes = new IdentityHashMap<>();
private final Map<SqlSelect, SqlValidatorScope> selectScopes = new IdentityHashMap<>();
private final Map<SqlSelect, SqlValidatorScope> orderScopes = new IdentityHashMap<>();
private final Map<SqlSelect, SqlValidatorScope> cursorScopes =new IdentityHashMap<>();
还有一个nameSpace 的 map
protected final Map<SqlNode, SqlValidatorNamespace> namespaces = new IdentityHashMap<>();
对于具体的registerQuery 这个方法,其实就是在填充上面这些map 的一个过程。
private void registerQuery(
SqlValidatorScope parentScope,
SqlValidatorScope usingScope,
SqlNode node,
SqlNode enclosingNode,
String alias,
boolean forceNullable,
boolean checkUpdate) {
Objects.requireNonNull(node);
Objects.requireNonNull(enclosingNode);
Preconditions.checkArgument(usingScope == null || alias != null);
SqlCall call;
List<SqlNode> operands;
switch (node.getKind()) { //根据node 的种类不同选择不同的case 分支
case SELECT:
final SqlSelect select = (SqlSelect) node; // 传入的这个topNode
final SelectNamespace selectNs =
createSelectNamespace(select, enclosingNode); // 新建这样一个SelectNamespace
registerNamespace(usingScope, alias, selectNs, forceNullable); // 注册nameSpace 的过程也就是把它放入nameSpace 的那个map 里面(SqlNode--> Namespace)
final SqlValidatorScope windowParentScope =
(usingScope != null) ? usingScope : parentScope;
SelectScope selectScope =
new SelectScope(parentScope, windowParentScope, select); // 新建这样一个SelectScope
//可以看到这个SelectScope 被放入了三个map ,一个scopes ,一个whereScopes ,一个selectScopes
scopes.put(select, selectScope);
// Start by registering the WHERE clause
whereScopes.put(select, selectScope);
registerOperandSubQueries(
selectScope,
select,
SqlSelect.WHERE_OPERAND);
// Register FROM with the inherited scope 'parentScope', not
// 'selectScope', otherwise tables in the FROM clause would be
// able to see each other.
final SqlNode from = select.getFrom(); // 对于一个select 的语句会有一个from 的表, 获取他from 的信息
if (from != null) {
final SqlNode newFrom =
registerFrom(
parentScope,
selectScope,
true,
from,
from,
null,
null,
false,
false);
if (newFrom != from) {
select.setFrom(newFrom);
}
}
// If this is an aggregating query, the SELECT list and HAVING
// clause use a different scope, where you can only reference
// columns which are in the GROUP BY clause.
SqlValidatorScope aggScope = selectScope;
if (isAggregate(select)) { // 是否是一个agg 类型的select
aggScope =
new AggregatingSelectScope(selectScope, select, false);
selectScopes.put(select, aggScope);
} else {
selectScopes.put(select, selectScope);// selectScopes 在这里放入
}
if (select.getGroup() != null) {
GroupByScope groupByScope =
new GroupByScope(selectScope, select.getGroup(), select);
groupByScopes.put(select, groupByScope);
registerSubQueries(groupByScope, select.getGroup());
}
//注册subQueries 过程暂时不必关注, 先分析最简单的一种情况
registerOperandSubQueries(
aggScope,
select,
SqlSelect.HAVING_OPERAND);
registerSubQueries(aggScope, select.getSelectList());
final SqlNodeList orderList = select.getOrderList();
if (orderList != null) {
// If the query is 'SELECT DISTINCT', restrict the columns
// available to the ORDER BY clause.
if (select.isDistinct()) {
aggScope =
new AggregatingSelectScope(selectScope, select, true);
}
//当前案例没有orderby
OrderByScope orderScope =
new OrderByScope(aggScope, orderList, select);
orderScopes.put(select, orderScope);
registerSubQueries(orderScope, orderList);
if (!isAggregate(select)) {
// Since this is not an aggregating query,
// there cannot be any aggregates in the ORDER BY clause.
SqlNode agg = aggFinder.findAgg(orderList);
if (agg != null) {
throw newValidationError(agg, RESOURCE.aggregateIllegalInOrderBy());
}
}
}
break;
注意在最初始 的时候, 可以看到这个Validator 对象。
Validate 在最开始我们注册进去两张表到rootSchema 以后。成为整个validate 的基准、
registerQuery
这里的功能主要就是将[元数据]转换成 SqlValidator 内部的 对象 进行表示,也就是 SqlValidatorScope 和 SqlValidatorNamespace 两种类型的对象:
SqlValidatorNamespace:a description of a data source used in a query,它代表了 SQL 查询的数据源,它是一个逻辑上数据源,可以是一张表,也可以是一个子查询;
SqlValidatorScope:describes the tables and columns accessible at a particular point in the query,代表了在某一个程序运行点,当前可见的字段名和表名。
网友评论