/** * A normal reduce operator's rowObjectInspector looks like a struct containing nested key/value * structs that contain the column values: { key: { reducesinkkey0:int }, value: { _col0:int, * _col1:int, .. } } * * <p>While the rowObjectInspector looks the same for vectorized queries during compilation time, * within the tasks at query execution the rowObjectInspector has changed to a flatter structure * without nested key/value structs: { 'key.reducesinkkey0':int, 'value._col0':int, * 'value._col1':int, .. } * * <p>Trying to fetch 'key.reducesinkkey0' by name from the list of flattened ObjectInspectors * does not work because the '.' gets interpreted as a field member, even though it is a flattened * list of column values. This workaround converts the column name referenced in the ExprNodeDesc * from a nested field name (key.reducesinkkey0) to key_reducesinkkey0, simply by replacing '.' * with '_'. * * @param source * @return */ public static ExprNodeDesc flattenExpr(ExprNodeDesc source) { if (source instanceof ExprNodeGenericFuncDesc) { // all children expression should be resolved ExprNodeGenericFuncDesc function = (ExprNodeGenericFuncDesc) source.clone(); List<ExprNodeDesc> newChildren = flattenExprList(function.getChildren()); for (ExprNodeDesc newChild : newChildren) { if (newChild == null) { // Could not resolve all of the function children, fail return null; } } function.setChildren(newChildren); return function; } if (source instanceof ExprNodeColumnDesc) { ExprNodeColumnDesc column = (ExprNodeColumnDesc) source; // Create a new ColumnInfo, replacing STRUCT.COLUMN with STRUCT_COLUMN String newColumn = column.getColumn().replace('.', '_'); return new ExprNodeColumnDesc(source.getTypeInfo(), newColumn, column.getTabAlias(), false); } if (source instanceof ExprNodeFieldDesc) { // field expression should be resolved ExprNodeFieldDesc field = (ExprNodeFieldDesc) source.clone(); ExprNodeDesc fieldDesc = flattenExpr(field.getDesc()); if (fieldDesc == null) { return null; } field.setDesc(fieldDesc); return field; } // constant or null expr, just return return source; }
// Resolve column expression to input expression by using expression mapping in current operator private static ExprNodeDesc backtrack( ExprNodeColumnDesc column, Operator<?> current, Operator<?> terminal) throws SemanticException { Map<String, ExprNodeDesc> mapping = current.getColumnExprMap(); if (mapping == null) { return backtrack((ExprNodeDesc) column, current, terminal); } ExprNodeDesc mapped = mapping.get(column.getColumn()); return mapped == null ? null : backtrack(mapped, current, terminal); }