ASTNodeOrigin 包含关于生成特定 ASTNode 对象的上下文信息。
例如,我们定义视图 create view v as select x+1 as y from t
,我们要处理查询 select v1.y from v as v1
。如果在执行查询前,执行了 ALTER TABLE t
改变了 x 的类型,导致查询语句的类型检查错误。当出现错误时,我们希望提供关于 v 的定义语句中出错的位置,而不是上层查询的错误位置。
/**
* ASTNodeOrigin contains contextual information about the object from whose
* definition a particular ASTNode originated. For example, suppose a view v is
* defined as <code>select x+1 as y from t</code>, and we're processing a query
* <code>select v1.y from v as v1</code>, and there's a type-checking problem
* with the expression <code>x+1</code> due to an ALTER TABLE on t subsequent to
* the creation of v. Then, when reporting the error, we want to provide the
* parser location with respect to the definition of v (rather than with respect
* to the top-level query, since that represents a completely different
* "parser coordinate system").
*
*<p>
*
* So, when expanding the definition of v while analyzing the top-level query,
* we tag each ASTNode with a reference to an ASTNodeOrign describing v and its
* usage within the query.
*/
public class ASTNodeOrigin {
private final String objectType;
private final String objectName;
private final String objectDefinition;
private final String usageAlias;
private final ASTNode usageNode;
}
ASTNodeOrigin 有两种应用,第一种是子查询,第二种是视图。
视图
当SQL 解析时,SemanticAnalyzer 发现用到的表是一个视图,调用replaceViewReferenceWithDefinition(qb, tab, tabName, alias);
。
private void replaceViewReferenceWithDefinition(QB qb, Table tab,
String tab_name, String alias) throws SemanticException {
ASTNode viewTree;
final ASTNodeOrigin viewOrigin = new ASTNodeOrigin("VIEW", tab.getTableName(),
tab.getViewExpandedText(), alias, qb.getParseInfo().getSrcForAlias(
alias));
try {
// Reparse text, passing null for context to avoid clobbering
// the top-level token stream.
String viewFullyQualifiedName = tab.getCompleteName();
String viewText = tab.getViewExpandedText();
TableMask viewMask = new TableMask(this, conf, false);
viewTree = ParseUtils.parse(viewText, ctx, tab.getCompleteName());
// viewTree 和子节点调用setOrigin(viewOrigin)
}
}
子查询
子查询构建的时候生成 originalSQASTOrigin
public QBSubQuery(String outerQueryId,
int sqIdx,
ASTNode subQueryAST,
ASTNode parentQueryExpression,
SubQueryTypeDef operator,
ASTNode originalSQAST,
Context ctx) {
super();
this.subQueryAST = subQueryAST;
this.parentQueryExpression = parentQueryExpression;
this.operator = operator;
this.outerQueryId = outerQueryId;
this.sqIdx = sqIdx;
this.alias = "sq_" + this.sqIdx;
this.numCorrExprsinSQ = 0;
this.numOuterCorrExprsForHaving = 0;
String s = ctx.getTokenRewriteStream().toString(
originalSQAST.getTokenStartIndex(), originalSQAST.getTokenStopIndex());
originalSQASTOrigin = new ASTNodeOrigin("SubQuery", alias, s, alias, originalSQAST);
numOfCorrelationExprsAddedToSQSelect = 0;
groupbyAddedToSQ = false;
if ( operator.getType() == SubQueryType.NOT_IN ) {
notInCheck = new NotInCheck();
}
subQueryDiagnostic = SubQueryDiagnostic.getRewrite(this, ctx.getTokenRewriteStream(), ctx);
}
在 subqueryRestrictionsCheck 方法里,调用 subQueryAST.setOrigin(originalSQASTOrigin);
。