in flink-connector-hive/src/main/java/org/apache/flink/table/planner/delegation/hive/HiveParserTypeCheckProcFactory.java [1480:1684]
public Object process(
Node nd, Stack<Node> stack, NodeProcessorCtx procCtx, Object... nodeOutputs)
throws SemanticException {
HiveParserTypeCheckCtx ctx = (HiveParserTypeCheckCtx) procCtx;
ExprNodeDesc desc = HiveParserTypeCheckProcFactory.processGByExpr(nd, procCtx);
if (desc != null) {
// Here we know nd represents a group by expression.
// During the DFS traversal of the AST, a descendant of nd likely set an
// error because a sub-tree of nd is unlikely to also be a group by
// expression. For example, in a query such as
// SELECT *concat(key)* FROM src GROUP BY concat(key), 'key' will be
// processed before 'concat(key)' and since 'key' is not a group by
// expression, an error will be set in ctx by ColumnExprProcessor.
// We can clear the global error when we see that it was set in a
// descendant node of a group by expression because
// processGByExpr() returns a ExprNodeDesc that effectively ignores
// its children. Although the error can be set multiple times by
// descendant nodes, DFS traversal ensures that the error only needs to
// be cleared once. Also, for a case like
// SELECT concat(value, concat(value))... the logic still works as the
// error is only set with the first 'value'; all node processors quit
// early if the global error is set.
if (isDescendant(nd, ctx.getErrorSrcNode())) {
ctx.setError(null, null);
}
return desc;
}
if (ctx.getError() != null) {
return null;
}
HiveParserASTNode expr = (HiveParserASTNode) nd;
/*
* A Windowing specification get added as a child to a UDAF invocation to distinguish it
* from similar UDAFs but on different windows.
* The UDAF is translated to a WindowFunction invocation in the PTFTranslator.
* So here we just return null for tokens that appear in a Window Specification.
* When the traversal reaches up to the UDAF invocation its ExprNodeDesc is build using the
* ColumnInfo in the InputRR. This is similar to how UDAFs are handled in Select lists.
* The difference is that there is translation for Window related tokens, so we just
* return null;
*/
if (windowingTokens.contains(expr.getType())) {
if (!ctx.getallowWindowing()) {
throw new SemanticException(
HiveParserUtils.generateErrorMessage(
expr,
ErrorMsg.INVALID_FUNCTION.getMsg(
"Windowing is not supported in the context")));
}
return null;
}
if (expr.getType() == HiveASTParser.TOK_SUBQUERY_OP
|| expr.getType() == HiveASTParser.TOK_QUERY) {
return null;
}
if (expr.getType() == HiveASTParser.TOK_TABNAME) {
return null;
}
if (expr.getType() == HiveASTParser.TOK_ALLCOLREF) {
if (!ctx.getallowAllColRef()) {
throw new SemanticException(
HiveParserUtils.generateErrorMessage(
expr,
ErrorMsg.INVALID_COLUMN.getMsg(
"All column reference is not supported in the context")));
}
HiveParserRowResolver input = ctx.getInputRR();
HiveParserExprNodeColumnListDesc columnList =
new HiveParserExprNodeColumnListDesc();
assert expr.getChildCount() <= 1;
if (expr.getChildCount() == 1) {
// table aliased (select a.*, for example)
HiveParserASTNode child = (HiveParserASTNode) expr.getChild(0);
assert child.getType() == HiveASTParser.TOK_TABNAME;
assert child.getChildCount() == 1;
String tableAlias = unescapeIdentifier(child.getChild(0).getText());
HashMap<String, ColumnInfo> columns = input.getFieldMap(tableAlias);
if (columns == null) {
throw new SemanticException(
HiveParserErrorMsg.getMsg(ErrorMsg.INVALID_TABLE_ALIAS, child));
}
for (Map.Entry<String, ColumnInfo> colMap : columns.entrySet()) {
ColumnInfo colInfo = colMap.getValue();
if (!colInfo.getIsVirtualCol()) {
columnList.addColumn(toExprNodeDesc(colInfo));
}
}
} else {
// all columns (select *, for example)
for (ColumnInfo colInfo : input.getColumnInfos()) {
if (!colInfo.getIsVirtualCol()) {
columnList.addColumn(toExprNodeDesc(colInfo));
}
}
}
return columnList;
}
// If the first child is a TOK_TABLE_OR_COL, and nodeOutput[0] is NULL,
// and the operator is a DOT, then it's a table column reference.
if (expr.getType() == HiveASTParser.DOT
&& expr.getChild(0).getType() == HiveASTParser.TOK_TABLE_OR_COL
&& nodeOutputs[0] == null) {
return processQualifiedColRef(ctx, expr, nodeOutputs);
}
// Return nulls for conversion operators
if (conversionFunctionTextHashMap.keySet().contains(expr.getType())
|| specialFunctionTextHashMap.keySet().contains(expr.getType())
|| expr.getToken().getType() == HiveASTParser.CharSetName
|| expr.getToken().getType() == HiveASTParser.CharSetLiteral) {
return null;
}
boolean isFunction =
(expr.getType() == HiveASTParser.TOK_FUNCTION
|| expr.getType() == HiveASTParser.TOK_FUNCTIONSTAR
|| expr.getType() == HiveASTParser.TOK_FUNCTIONDI);
if (!ctx.getAllowDistinctFunctions()
&& expr.getType() == HiveASTParser.TOK_FUNCTIONDI) {
throw new SemanticException(
HiveParserUtils.generateErrorMessage(
expr, ErrorMsg.DISTINCT_NOT_SUPPORTED.getMsg()));
}
// Create all children
int childrenBegin = (isFunction ? 1 : 0);
ArrayList<ExprNodeDesc> children =
new ArrayList<>(expr.getChildCount() - childrenBegin);
for (int ci = childrenBegin; ci < expr.getChildCount(); ci++) {
if (nodeOutputs[ci] instanceof HiveParserExprNodeColumnListDesc) {
children.addAll(
((HiveParserExprNodeColumnListDesc) nodeOutputs[ci]).getChildren());
} else {
children.add((ExprNodeDesc) nodeOutputs[ci]);
}
}
if (expr.getType() == HiveASTParser.TOK_FUNCTIONSTAR) {
if (!ctx.getallowFunctionStar()) {
throw new SemanticException(
HiveParserUtils.generateErrorMessage(
expr,
ErrorMsg.INVALID_COLUMN.getMsg(
".* reference is not supported in the context")));
}
HiveParserRowResolver input = ctx.getInputRR();
for (ColumnInfo colInfo : input.getColumnInfos()) {
if (!colInfo.getIsVirtualCol()) {
children.add(toExprNodeDesc(colInfo));
}
}
}
// If any of the children contains null, then return a null
// this is a hack for now to handle the group by case
if (children.contains(null)) {
List<String> possibleColumnNames = getReferenceableColumnAliases(ctx);
String reason =
String.format(
"(possible column names are: %s)",
StringUtils.join(possibleColumnNames, ", "));
ctx.setError(
HiveParserErrorMsg.getMsg(
ErrorMsg.INVALID_COLUMN, expr.getChild(0), reason),
expr);
return null;
}
// Create function desc
try {
return getXpathOrFuncExprNodeDesc(expr, isFunction, children, ctx);
} catch (UDFArgumentTypeException e) {
throw new SemanticException(
HiveParserErrorMsg.getMsg(
ErrorMsg.INVALID_ARGUMENT_TYPE,
expr.getChild(childrenBegin + e.getArgumentId()),
e.getMessage()),
e);
} catch (UDFArgumentLengthException e) {
throw new SemanticException(
HiveParserErrorMsg.getMsg(
ErrorMsg.INVALID_ARGUMENT_LENGTH, expr, e.getMessage()),
e);
} catch (UDFArgumentException e) {
throw new SemanticException(
HiveParserErrorMsg.getMsg(ErrorMsg.INVALID_ARGUMENT, expr, e.getMessage()),
e);
}
}