Skip to content

Commit 91e888f

Browse files
imaychenhao7253886
authored andcommitted
Add converter to convert expression to plan node (#1245)
1 parent b0669c3 commit 91e888f

16 files changed

+457
-27
lines changed

fe/src/main/java/org/apache/doris/analysis/CaseWhenClause.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
/**
2222
* captures info of a single WHEN expr THEN expr clause.
2323
*/
24-
class CaseWhenClause {
24+
public class CaseWhenClause {
2525
private final Expr whenExpr;
2626
private final Expr thenExpr;
2727

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.apache.doris.optimizer;
19+
20+
import com.google.common.collect.Lists;
21+
import org.apache.doris.analysis.ArithmeticExpr;
22+
import org.apache.doris.analysis.BinaryPredicate;
23+
import org.apache.doris.analysis.CaseExpr;
24+
import org.apache.doris.analysis.CaseWhenClause;
25+
import org.apache.doris.analysis.CastExpr;
26+
import org.apache.doris.analysis.CompoundPredicate;
27+
import org.apache.doris.analysis.Expr;
28+
import org.apache.doris.analysis.FunctionCallExpr;
29+
import org.apache.doris.analysis.InPredicate;
30+
import org.apache.doris.analysis.IsNullPredicate;
31+
import org.apache.doris.analysis.LikePredicate;
32+
import org.apache.doris.analysis.SlotDescriptor;
33+
import org.apache.doris.analysis.SlotRef;
34+
import org.apache.doris.common.UserException;
35+
import org.apache.doris.optimizer.operator.OptItemArithmetic;
36+
import org.apache.doris.optimizer.operator.OptItemBinaryPredicate;
37+
import org.apache.doris.optimizer.operator.OptItemCase;
38+
import org.apache.doris.optimizer.operator.OptItemCast;
39+
import org.apache.doris.optimizer.operator.OptItemColumnRef;
40+
import org.apache.doris.optimizer.operator.OptItemCompoundPredicate;
41+
import org.apache.doris.optimizer.operator.OptItemConst;
42+
import org.apache.doris.optimizer.operator.OptItemFunctionCall;
43+
import org.apache.doris.optimizer.operator.OptItemInPredicate;
44+
import org.apache.doris.optimizer.operator.OptItemIsNullPredicate;
45+
import org.apache.doris.optimizer.operator.OptItemLikePredicate;
46+
import org.apache.doris.optimizer.operator.OptOperator;
47+
import org.apache.doris.optimizer.operator.OptPhysicalMysqlScan;
48+
import org.apache.doris.planner.MysqlScanNode;
49+
import org.apache.doris.planner.PlanNode;
50+
import org.apache.logging.log4j.LogManager;
51+
import org.apache.logging.log4j.Logger;
52+
53+
import java.util.List;
54+
55+
// Convert expression to statement, used to convert optimized expression
56+
// to a plan tree
57+
public class ExpressionToStmtConverter {
58+
private static final Logger LOG = LogManager.getLogger(ExpressionToStmtConverter.class);
59+
60+
private OptConverterCtx ctx;
61+
62+
public ExpressionToStmtConverter(OptConverterCtx ctx) {
63+
this.ctx = ctx;
64+
}
65+
66+
public PlanNode convertPhysical(OptExpression expr) {
67+
OptOperator op = expr.getOp();
68+
switch (op.getType()) {
69+
case OP_PHYSICAL_MYSQL_SCAN:
70+
return convertMysqlScan(expr)
71+
}
72+
return null;
73+
}
74+
75+
public MysqlScanNode convertMysqlScan(OptExpression expr) {
76+
OptPhysicalMysqlScan scanOp = (OptPhysicalMysqlScan) expr.getOp();
77+
MysqlScanNode node = new MysqlScanNode()
78+
return null;
79+
}
80+
81+
public Expr convertItem(OptExpression expr) throws UserException {
82+
OptOperator op = expr.getOp();
83+
switch (op.getType()) {
84+
case OP_ITEM_BINARY_PREDICATE:
85+
return convertBinaryPred(expr);
86+
case OP_ITEM_COMPOUND_PREDICATE:
87+
return convertCompoundPred(expr);
88+
case OP_ITEM_CONST:
89+
return convertConst(expr);
90+
case OP_ITEM_ARITHMETIC:
91+
return convertArithmetic(expr);
92+
case OP_ITEM_CASE:
93+
return convertCase(expr);
94+
case OP_ITEM_CAST:
95+
return convertCast(expr);
96+
case OP_ITEM_FUNCTION_CALL:
97+
return convertFunctionCall(expr);
98+
case OP_ITEM_AGG_FUNC:
99+
return convertAggregateFunction(expr);
100+
case OP_ITEM_COLUMN_REF:
101+
return convertColumnRef(expr);
102+
case OP_ITEM_IN_PREDICATE:
103+
return convertInPred(expr);
104+
case OP_ITEM_LIKE_PREDICATE:
105+
return convertLikePred(expr);
106+
case OP_ITEM_IS_NULL_PREDICATE:
107+
return convertIsNullPred(expr);
108+
}
109+
}
110+
111+
private Expr convertConst(OptExpression expr) {
112+
return ((OptItemConst) expr.getOp()).getLiteral();
113+
}
114+
115+
private Expr convertIsNullPred(OptExpression expr) throws UserException {
116+
Expr child = convertItem(expr.getInput(0));
117+
OptItemIsNullPredicate pred = (OptItemIsNullPredicate) expr.getOp();
118+
return new IsNullPredicate(child, pred.isNotNull());
119+
}
120+
121+
private Expr convertLikePred(OptExpression expr) throws UserException {
122+
Expr leftChild = convertItem(expr.getInput(0));
123+
Expr rightChild = convertItem(expr.getInput(0));
124+
OptItemLikePredicate pred = (OptItemLikePredicate) expr.getOp();
125+
return new LikePredicate(pred.getOp(), leftChild, rightChild);
126+
}
127+
128+
private Expr convertInPred(OptExpression expr) throws UserException {
129+
Expr compareChild = convertItem(expr.getInput(0));
130+
131+
List<Expr> children = Lists.newArrayList();
132+
for (int i = 1; i < expr.getInputs().size(); ++i) {
133+
children.add(convertItem(expr.getInput(i)));
134+
}
135+
136+
OptItemInPredicate pred = (OptItemInPredicate) expr.getOp();
137+
return new InPredicate(compareChild, children, pred.isNotIn());
138+
}
139+
140+
private Expr convertColumnRef(OptExpression expr) throws UserException {
141+
OptItemColumnRef columnRef = (OptItemColumnRef) expr.getOp();
142+
SlotDescriptor slotDesc = ctx.getSlotRef(columnRef.getRef().getId());
143+
if (slotDesc == null) {
144+
LOG.warn("fail to get SlotRef with ColumnRef, columnRef={}", columnRef.getRef());
145+
throw new UserException("Unknown column reference");
146+
}
147+
return new SlotRef(slotDesc);
148+
}
149+
150+
private Expr convertAggregateFunction(OptExpression expr) {
151+
return null;
152+
}
153+
154+
private Expr convertCast(OptExpression expr) throws UserException {
155+
Expr child = convertItem(expr.getInput(0));
156+
OptItemCast op = (OptItemCast) expr.getOp();
157+
return new CastExpr(op.getDestType(), child);
158+
}
159+
160+
private Expr convertCase(OptExpression expr) throws UserException {
161+
OptItemCase caseOp = (OptItemCase) expr.getOp();
162+
Expr caseExpr = null;
163+
int idx = 0;
164+
if (caseOp.hasCase()) {
165+
caseExpr = convertItem(expr.getInput(idx));
166+
idx++;
167+
}
168+
int endIdx = expr.getInputs().size();
169+
Expr elseExpr = null;
170+
if (caseOp.hasElse()) {
171+
endIdx--;
172+
elseExpr = convertItem(expr.getInput(endIdx));
173+
}
174+
if ((endIdx - idx) % 2 != 0) {
175+
throw new UserException("");
176+
}
177+
List<CaseWhenClause> whenThenList = Lists.newArrayList();
178+
for (; idx < endIdx; idx += 2) {
179+
Expr whenExpr = convertItem(expr.getInput(idx));
180+
Expr thenExpr = convertItem(expr.getInput(idx + 1));
181+
whenThenList.add(new CaseWhenClause(whenExpr, thenExpr));
182+
}
183+
184+
return new CaseExpr(caseExpr, whenThenList, elseExpr);
185+
}
186+
187+
private Expr convertArithmetic(OptExpression expr) throws UserException {
188+
Expr leftChild = convertItem(expr.getInput(0));
189+
Expr rightChild = null;
190+
if (expr.getInputs().size() == 2) {
191+
rightChild = convertItem(expr.getInput(1));
192+
}
193+
OptItemArithmetic item = (OptItemArithmetic) expr.getOp();
194+
return new ArithmeticExpr(item.getOp(), leftChild, rightChild);
195+
}
196+
197+
private Expr convertBinaryPred(OptExpression expr) throws UserException {
198+
Expr leftChild = convertItem(expr.getInput(0));
199+
Expr rightChild = convertItem(expr.getInput(1));
200+
201+
OptItemBinaryPredicate pred = (OptItemBinaryPredicate) expr.getOp();
202+
return new BinaryPredicate(pred.getOp(), leftChild, rightChild);
203+
}
204+
205+
private Expr convertCompoundPred(OptExpression expr) throws UserException {
206+
OptItemCompoundPredicate pred = (OptItemCompoundPredicate) expr.getOp();
207+
Expr leftChild = convertItem(expr.getInput(0));
208+
Expr rightChild = null;
209+
if (pred.getOp() != CompoundPredicate.Operator.NOT) {
210+
rightChild = convertItem(expr.getInput(1));
211+
}
212+
return new CompoundPredicate(pred.getOp(), leftChild, rightChild);
213+
}
214+
215+
private Expr convertFunctionCall(OptExpression expr) throws UserException {
216+
OptItemFunctionCall funcOp = (OptItemFunctionCall) expr.getOp();
217+
218+
List<Expr> children = Lists.newArrayList();
219+
for (OptExpression input : expr.getInputs()) {
220+
children.add(convertItem(input));
221+
}
222+
223+
return new FunctionCallExpr(funcOp.getName(), children);
224+
}
225+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.apache.doris.optimizer;
19+
20+
import com.google.common.collect.Lists;
21+
import com.google.common.collect.Maps;
22+
import org.apache.doris.analysis.SlotDescriptor;
23+
import org.apache.doris.analysis.SlotRef;
24+
import org.apache.doris.analysis.TupleDescriptor;
25+
import org.apache.doris.common.IdGenerator;
26+
import org.apache.doris.optimizer.base.OptColumnRef;
27+
import org.apache.doris.optimizer.base.OptColumnRefFactory;
28+
import org.apache.doris.planner.PlanNodeId;
29+
30+
import java.util.List;
31+
import java.util.Map;
32+
33+
// Used to record information when converting statement to optimization's expression
34+
// and convert optimized expression back to plan node
35+
public class OptConverterCtx {
36+
private OptColumnRefFactory columnRefFactory = new OptColumnRefFactory();
37+
private Map<Integer, OptColumnRef> slotIdToColumnRef = Maps.newHashMap();
38+
// map from OptColumnRef to SlotReference,
39+
private Map<Integer, SlotDescriptor> columnIdToSlotRef = Maps.newHashMap();
40+
private IdGenerator<PlanNodeId> planNodeIdGenerator = PlanNodeId.createGenerator();
41+
42+
// Convert a TupleDescriptor to a list of OptColumnRef and record map information
43+
public List<OptColumnRef> convertTuple(TupleDescriptor tupleDesc) {
44+
List<OptColumnRef> columnRefs = Lists.newArrayList();
45+
for (SlotDescriptor slotDesc : tupleDesc.getSlots()) {
46+
columnRefs.add(createColumnRef(slotDesc));
47+
}
48+
return columnRefs;
49+
}
50+
51+
// used to convert statement to OptExpression
52+
public OptColumnRef getColumnRef(int slotId) {
53+
return slotIdToColumnRef.get(slotId);
54+
}
55+
56+
// used to convert OptExpression to PlanNode
57+
public SlotDescriptor getSlotRef(int columnId) {
58+
return columnIdToSlotRef.get(columnId);
59+
}
60+
61+
public PlanNodeId nextPlanNodeId() {
62+
return planNodeIdGenerator.getNextId();
63+
}
64+
65+
private OptColumnRef createColumnRef(SlotDescriptor slotDesc) {
66+
OptColumnRef columnRef = columnRefFactory.create(slotDesc.getLabel(), slotDesc.getType());
67+
slotIdToColumnRef.put(slotDesc.getId().asInt(), columnRef);
68+
columnIdToSlotRef.put(columnRef.getId(), slotDesc);
69+
return columnRef;
70+
}
71+
}

fe/src/main/java/org/apache/doris/optimizer/StmtToExpressionConvertor.java fe/src/main/java/org/apache/doris/optimizer/StmtToExpressionConverter.java

+12-15
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,17 @@
5353
import java.util.Map;
5454

5555
// Used to convert QueryStmt to an OptExpression
56-
public class StmtToExpressionConvertor {
56+
public class StmtToExpressionConverter {
5757
private OptColumnRefFactory columnRefFactory = new OptColumnRefFactory();
5858
private Map<Integer, OptColumnRef> slotIdToColumnRef = Maps.newHashMap();
59+
// map from OptColumnRef to SlotReference
60+
private Map<Integer, SlotRef> columnIdToSlotRef = Maps.newHashMap();
61+
62+
private OptConverterCtx ctx;
63+
64+
public StmtToExpressionConverter(OptConverterCtx ctx) {
65+
this.ctx = ctx;
66+
}
5967

6068
public OptExpression convertQuery(QueryStmt stmt) {
6169
OptExpression root;
@@ -152,7 +160,7 @@ public OptExpression convertTableRef(TableRef ref) {
152160
}
153161

154162
public OptExpression convertBaseTableRef(BaseTableRef ref) {
155-
List<OptColumnRef> columnRefs = convertTuple(ref.getDesc());
163+
List<OptColumnRef> columnRefs = ctx.convertTuple(ref.getDesc());
156164
OptLogical op = null;
157165
switch (ref.getTable().getType()) {
158166
case OLAP:
@@ -168,7 +176,7 @@ private OptExpression convertInlineView(InlineViewRef ref) {
168176

169177
List<Expr> resultExprs = ref.getViewStmt().getResultExprs();
170178

171-
List<OptColumnRef> columnRefs = convertTuple(ref.getDesc());
179+
List<OptColumnRef> columnRefs = ctx.convertTuple(ref.getDesc());
172180

173181
List<OptExpression> projElements = Lists.newArrayList();
174182
for (int i = 0 ; i < columnRefs.size(); ++i) {
@@ -180,17 +188,6 @@ private OptExpression convertInlineView(InlineViewRef ref) {
180188
return OptExpression.create(new OptLogicalProject(), childExpr, projList);
181189
}
182190

183-
private List<OptColumnRef> convertTuple(TupleDescriptor desc) {
184-
List<OptColumnRef> refs = Lists.newArrayList();
185-
for (SlotDescriptor slot : desc.getSlots()) {
186-
OptColumnRef ref = columnRefFactory.create(slot.getLabel(), slot.getType());
187-
188-
slotIdToColumnRef.put(slot.getId().asInt(), ref);
189-
refs.add(ref);
190-
}
191-
return refs;
192-
}
193-
194191
public OptExpression convertExpr(Expr expr) {
195192
if (expr instanceof BinaryPredicate) {
196193
return convertBinaryPredicate((BinaryPredicate) expr);
@@ -236,7 +233,7 @@ private OptExpression convertArithmeticExpr(ArithmeticExpr expr) {
236233
}
237234

238235
private OptExpression convertSlotRef(SlotRef ref) {
239-
OptColumnRef columnRef = slotIdToColumnRef.get(ref.getSlotId().asInt());
236+
OptColumnRef columnRef = ctx.getColumnRef(ref.getSlotId().asInt());
240237
Preconditions.checkArgument(columnRef != null,
241238
"Can not find ColumnRef through ref, ref=" + ref.debugString());
242239

fe/src/main/java/org/apache/doris/optimizer/operator/OptItemArithmetic.java

+9
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@
2121
import org.apache.doris.catalog.Type;
2222
import org.apache.doris.optimizer.OptUtils;
2323

24+
// In common case, the OptItemArithmetic has two children. Such as 'add', 'minus'
25+
// OptItemArithmetic
26+
// |--- OptItem(left child)
27+
// |--- OptItem(right child)
28+
// But for some cases, this has only one child, such as 'bitnot'
29+
// OptItemArithmetic
30+
// |--- OptItem(left child)
2431
public class OptItemArithmetic extends OptItem {
2532
private ArithmeticExpr.Operator op;
2633

@@ -29,6 +36,8 @@ public OptItemArithmetic(ArithmeticExpr.Operator op) {
2936
this.op = op;
3037
}
3138

39+
public ArithmeticExpr.Operator getOp() { return op; }
40+
3241
@Override
3342
public Type getReturnType() {
3443
return null;

0 commit comments

Comments
 (0)