[Lateral View] Multi lateral views map one TableFunctionNode (#7000)
1. Forbidden non-string column as params of explode_view.
The first param of explode_view must be string column(VARCHAR/CHAR/STRING)
2. N-1 n lateral views map one TableFunctionNode
The TableFunctionNode include all of fnExprs which belongs to one table.
For example:
select pageid,mycol1, mycol2 from pageAds
lateral view explode_string(col1) myTable1 as mycol1
lateral view explode_string(col2) myTable2 as mycol2;
TableFunctionNode
|----
|- fnExprList: explode_string(col1), explode_string(col2)
This commit is contained in:
@ -98,6 +98,9 @@ public class LateralViewRef extends TableRef {
|
||||
if (originColumn == null) {
|
||||
throw new AnalysisException("The explode column must be a real column in table");
|
||||
}
|
||||
if (!originColumn.getType().isStringType()) {
|
||||
throw new AnalysisException("The explode column must be VARCHAR/CHAR/STRING type");
|
||||
}
|
||||
// analyze lateral view
|
||||
desc = analyzer.registerTableRef(this);
|
||||
explodeSlotRef = new SlotRef(new TableName(null, viewName), columnName);
|
||||
|
||||
@ -1882,12 +1882,10 @@ public class SingleNodePlanner {
|
||||
throws UserException {
|
||||
Preconditions.checkNotNull(lateralViewRefs);
|
||||
Preconditions.checkState(lateralViewRefs.size() > 0);
|
||||
for (LateralViewRef lateralViewRef: lateralViewRefs) {
|
||||
TableFunctionNode tableFunctionNode = new TableFunctionNode(ctx_.getNextNodeId(), inputNode,
|
||||
lateralViewRef);
|
||||
tableFunctionNode.init(analyzer);
|
||||
inputNode = tableFunctionNode;
|
||||
}
|
||||
TableFunctionNode tableFunctionNode = new TableFunctionNode(ctx_.getNextNodeId(), inputNode,
|
||||
lateralViewRefs);
|
||||
tableFunctionNode.init(analyzer);
|
||||
inputNode = tableFunctionNode;
|
||||
return inputNode;
|
||||
}
|
||||
|
||||
|
||||
@ -18,34 +18,41 @@
|
||||
package org.apache.doris.planner;
|
||||
|
||||
import org.apache.doris.analysis.Analyzer;
|
||||
import org.apache.doris.analysis.Expr;
|
||||
import org.apache.doris.analysis.FunctionCallExpr;
|
||||
import org.apache.doris.analysis.LateralViewRef;
|
||||
import org.apache.doris.analysis.TupleId;
|
||||
import org.apache.doris.common.UserException;
|
||||
import org.apache.doris.thrift.TExplainLevel;
|
||||
import org.apache.doris.thrift.TPlanNode;
|
||||
import org.apache.doris.thrift.TPlanNodeType;
|
||||
import org.apache.doris.thrift.TTableFunctionNode;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class TableFunctionNode extends PlanNode {
|
||||
|
||||
private LateralViewRef lateralViewRef;
|
||||
private List<LateralViewRef> lateralViewRefs;
|
||||
private List<FunctionCallExpr> fnCallExprList;
|
||||
private List<TupleId> lateralViewTupleIds;
|
||||
|
||||
private FunctionCallExpr fnCallExpr;
|
||||
|
||||
protected TableFunctionNode(PlanNodeId id, PlanNode inputNode, LateralViewRef lateralViewRef) {
|
||||
protected TableFunctionNode(PlanNodeId id, PlanNode inputNode, List<LateralViewRef> lateralViewRefs) {
|
||||
super(id, "TABLE FUNCTION NODE");
|
||||
tupleIds.addAll(inputNode.getTupleIds());
|
||||
tblRefIds.addAll(inputNode.getTupleIds());
|
||||
tupleIds.add(lateralViewRef.getDesc().getId());
|
||||
tblRefIds.add(lateralViewRef.getDesc().getId());
|
||||
lateralViewTupleIds = lateralViewRefs.stream().map(e -> e.getDesc().getId())
|
||||
.collect(Collectors.toList());
|
||||
tupleIds.addAll(lateralViewTupleIds);
|
||||
tblRefIds.addAll(lateralViewTupleIds);
|
||||
children.add(inputNode);
|
||||
this.lateralViewRef = lateralViewRef;
|
||||
this.lateralViewRefs = lateralViewRefs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Analyzer analyzer) throws UserException {
|
||||
super.init(analyzer);
|
||||
fnCallExpr = lateralViewRef.getFnExpr();
|
||||
fnCallExprList = lateralViewRefs.stream().map(e -> e.getFnExpr()).collect(Collectors.toList());
|
||||
computeStats(analyzer);
|
||||
}
|
||||
|
||||
@ -59,11 +66,28 @@ public class TableFunctionNode extends PlanNode {
|
||||
@Override
|
||||
public String getNodeExplainString(String prefix, TExplainLevel detailLevel) {
|
||||
StringBuilder output = new StringBuilder();
|
||||
output.append(prefix + "table function: ").append(fnCallExpr.toSql() + "\n");
|
||||
output.append(prefix + "table function: ");
|
||||
for (FunctionCallExpr fnExpr : fnCallExprList) {
|
||||
output.append(fnExpr.toSqlImpl() + " ");
|
||||
}
|
||||
output.append("\n");
|
||||
|
||||
output.append(prefix + "lateral view tuple id: ");
|
||||
for (TupleId tupleId : lateralViewTupleIds) {
|
||||
output.append(tupleId.asInt() + " ");
|
||||
}
|
||||
output.append("\n");
|
||||
|
||||
if (detailLevel == TExplainLevel.BRIEF) {
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
output.append(prefix + "tuple id: ");
|
||||
for (TupleId tupleId : tupleIds) {
|
||||
output.append(tupleId.asInt() + " ");
|
||||
}
|
||||
output.append("\n");
|
||||
|
||||
if (!conjuncts.isEmpty()) {
|
||||
output.append(prefix).append("PREDICATES: ").append(
|
||||
getExplainString(conjuncts)).append("\n");
|
||||
@ -76,6 +100,6 @@ public class TableFunctionNode extends PlanNode {
|
||||
protected void toThrift(TPlanNode msg) {
|
||||
msg.node_type = TPlanNodeType.TABLE_FUNCTION_NODE;
|
||||
msg.table_function_node = new TTableFunctionNode();
|
||||
msg.table_function_node.setFnCallExpr(fnCallExpr.treeToThrift());
|
||||
msg.table_function_node.setFnCallExprList(Expr.treesToThrift(fnCallExprList));
|
||||
}
|
||||
}
|
||||
|
||||
@ -150,12 +150,9 @@ public class TableFunctionPlanTest {
|
||||
String sql = "desc verbose select k1, e1, e2 from db1.tbl1 lateral view explode_split(k2, \",\") tmp1 as e1"
|
||||
+ " lateral view explode_split(k2, \",\") tmp2 as e2;";
|
||||
String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(ctx, sql, true);
|
||||
Assert.assertTrue(explainString.contains("2:TABLE FUNCTION NODE"));
|
||||
Assert.assertTrue(explainString.contains("table function: explode_split(`k2`, ',')"));
|
||||
Assert.assertTrue(explainString.contains("tuple ids: 0 1 2"));
|
||||
Assert.assertTrue(explainString.contains("1:TABLE FUNCTION NODE"));
|
||||
Assert.assertTrue(explainString.contains("table function: explode_split(`k2`, ',')"));
|
||||
Assert.assertTrue(explainString.contains("tuple ids: 0 1"));
|
||||
Assert.assertTrue(explainString.contains("table function: explode_split(`k2`, ',') explode_split(`k2`, ',')"));
|
||||
Assert.assertTrue(explainString.contains("lateral view tuple id: 1 2"));
|
||||
// lateral view 2 tuple
|
||||
Assert.assertTrue(explainString.contains("TupleDescriptor{id=1, tbl=tmp2, byteSize=32, materialized=true}"));
|
||||
Assert.assertTrue(explainString.contains("SlotDescriptor{id=1, col=e2, type=VARCHAR(*)}"));
|
||||
|
||||
@ -657,7 +657,7 @@ struct TOlapRewriteNode {
|
||||
}
|
||||
|
||||
struct TTableFunctionNode {
|
||||
1: required Exprs.TExpr fnCallExpr
|
||||
1: required list<Exprs.TExpr> fnCallExprList
|
||||
}
|
||||
|
||||
// This contains all of the information computed by the plan as part of the resource
|
||||
|
||||
Reference in New Issue
Block a user