[refactor](complex-type) refactor array/map/struct literal to not invoke execute() function in prepare state (#19068)
This commit is contained in:
@ -23,6 +23,7 @@ import org.apache.doris.common.AnalysisException;
|
||||
import org.apache.doris.thrift.TExprNode;
|
||||
import org.apache.doris.thrift.TExprNodeType;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.DataInput;
|
||||
@ -60,19 +61,26 @@ public class ArrayLiteral extends LiteralExpr {
|
||||
type = new ArrayType(itemType, containsNull);
|
||||
|
||||
children = new ArrayList<>();
|
||||
for (LiteralExpr expr : exprs) {
|
||||
if (expr.getType().equals(itemType)) {
|
||||
children.add(expr);
|
||||
} else {
|
||||
children.add(expr.castTo(itemType));
|
||||
try {
|
||||
for (LiteralExpr expr : exprs) {
|
||||
if (expr.getType().equals(itemType)) {
|
||||
children.add(expr);
|
||||
} else {
|
||||
children.add(expr.convertTo(itemType));
|
||||
}
|
||||
}
|
||||
} catch (AnalysisException e) {
|
||||
String s = "[" + StringUtils.join(exprs, ',') + "]";
|
||||
throw new AnalysisException("Invalid ARRAY " + s + " literal: " + e.getMessage());
|
||||
}
|
||||
analysisDone();
|
||||
}
|
||||
|
||||
protected ArrayLiteral(ArrayLiteral other) {
|
||||
super(other);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isMinValue() {
|
||||
return false;
|
||||
@ -103,7 +111,7 @@ public class ArrayLiteral extends LiteralExpr {
|
||||
public String getStringValue() {
|
||||
List<String> list = new ArrayList<>(children.size());
|
||||
children.forEach(v -> list.add(v.getStringValue()));
|
||||
return "ARRAY[" + StringUtils.join(list, ", ") + "]";
|
||||
return "[" + StringUtils.join(list, ", ") + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -149,15 +157,32 @@ public class ArrayLiteral extends LiteralExpr {
|
||||
return new ArrayLiteral(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiteralExpr convertTo(Type targetType) throws AnalysisException {
|
||||
Preconditions.checkState(targetType instanceof ArrayType);
|
||||
Type itemType = ((ArrayType) targetType).getItemType();
|
||||
LiteralExpr[] literals = new LiteralExpr[children.size()];
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
literals[i] = (LiteralExpr) (Expr.convertLiteral(children.get(i), itemType));
|
||||
}
|
||||
return new ArrayLiteral(literals);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expr uncheckedCastTo(Type targetType) throws AnalysisException {
|
||||
if (!targetType.isArrayType()) {
|
||||
return super.uncheckedCastTo(targetType);
|
||||
}
|
||||
Type itemType = ((ArrayType) targetType).getItemType();
|
||||
ArrayLiteral literal = new ArrayLiteral(this);
|
||||
for (int i = 0; i < children.size(); ++ i) {
|
||||
Expr child = children.get(i);
|
||||
literal.children.set(i, child.uncheckedCastTo(((ArrayType) targetType).getItemType()));
|
||||
Expr child = Expr.convertLiteral(children.get(i), itemType);
|
||||
// all children should be literal or else it will make be core
|
||||
if (!child.isLiteral()) {
|
||||
throw new AnalysisException("Unexpected array literal cast failed. from type: "
|
||||
+ this.type + ", to type: " + targetType);
|
||||
}
|
||||
literal.children.set(i, child);
|
||||
}
|
||||
literal.setType(targetType);
|
||||
return literal;
|
||||
|
||||
@ -453,6 +453,11 @@ public class CastExpr extends Expr {
|
||||
Expr targetExpr;
|
||||
try {
|
||||
targetExpr = castTo((LiteralExpr) value);
|
||||
if (targetTypeDef != null) {
|
||||
targetExpr.setType(targetTypeDef.getType());
|
||||
} else {
|
||||
targetExpr.setType(type);
|
||||
}
|
||||
} catch (AnalysisException ae) {
|
||||
targetExpr = this;
|
||||
} catch (NumberFormatException nfe) {
|
||||
|
||||
@ -1485,6 +1485,21 @@ public abstract class Expr extends TreeNode<Expr> implements ParseNode, Cloneabl
|
||||
setChild(childIndex, newChild);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assuming it can cast to the targetType, use for convert literal value to
|
||||
* target type without a cast node.
|
||||
*/
|
||||
public static Expr convertLiteral(Expr expr, Type targetType) throws AnalysisException {
|
||||
if (!(expr instanceof LiteralExpr)) {
|
||||
return expr;
|
||||
}
|
||||
Expr newExpr = expr.uncheckedCastTo(targetType);
|
||||
if (newExpr instanceof CastExpr) {
|
||||
return ((LiteralExpr) newExpr.getChild(0)).convertTo(targetType);
|
||||
}
|
||||
return newExpr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a cast expression above child.
|
||||
* If child is a literal expression, we attempt to
|
||||
|
||||
@ -1575,7 +1575,9 @@ public class FunctionCallExpr extends Expr {
|
||||
|| fnName.getFunction().equalsIgnoreCase("array_concat")
|
||||
|| fnName.getFunction().equalsIgnoreCase("array_shuffle")
|
||||
|| fnName.getFunction().equalsIgnoreCase("shuffle")
|
||||
|| fnName.getFunction().equalsIgnoreCase("array_except"))
|
||||
|| fnName.getFunction().equalsIgnoreCase("array_except")
|
||||
|| fnName.getFunction().equalsIgnoreCase("array_contains")
|
||||
|| fnName.getFunction().equalsIgnoreCase("array_position"))
|
||||
&& ((args[ix].isDecimalV3())
|
||||
|| (children.get(0).getType().isArrayType()
|
||||
&& (((ArrayType) children.get(0).getType()).getItemType().isDecimalV3())
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
package org.apache.doris.analysis;
|
||||
|
||||
import org.apache.doris.catalog.PrimitiveType;
|
||||
import org.apache.doris.catalog.ScalarType;
|
||||
import org.apache.doris.catalog.Type;
|
||||
import org.apache.doris.common.AnalysisException;
|
||||
import org.apache.doris.common.NotImplementedException;
|
||||
@ -137,6 +138,39 @@ public abstract class LiteralExpr extends Expr implements Comparable<LiteralExpr
|
||||
return literalExpr;
|
||||
}
|
||||
|
||||
public Expr convertTo(Type targetType) throws AnalysisException {
|
||||
Preconditions.checkArgument(!targetType.equals(Type.INVALID));
|
||||
if (this instanceof NullLiteral) {
|
||||
return NullLiteral.create(targetType);
|
||||
} else if (targetType.isBoolean()) {
|
||||
if (this instanceof StringLiteral || this instanceof JsonLiteral) {
|
||||
return new BoolLiteral(getStringValue());
|
||||
} else {
|
||||
if (getLongValue() != 0) {
|
||||
return new BoolLiteral(true);
|
||||
} else {
|
||||
return new BoolLiteral(false);
|
||||
}
|
||||
}
|
||||
} else if (targetType.isIntegerType()) {
|
||||
return new IntLiteral(getLongValue(), targetType);
|
||||
} else if (targetType.isLargeIntType()) {
|
||||
return new LargeIntLiteral(getStringValue());
|
||||
} else if (targetType.isFloatingPointType()) {
|
||||
return new FloatLiteral(getDoubleValue(), targetType);
|
||||
} else if (targetType.isDecimalV2() || targetType.isDecimalV3()) {
|
||||
DecimalLiteral literal = new DecimalLiteral(getStringValue(),
|
||||
((ScalarType) targetType).getScalarScale());
|
||||
literal.setType(targetType);
|
||||
return literal;
|
||||
} else if (targetType.isStringType()) {
|
||||
return new StringLiteral(getStringValue());
|
||||
} else if (targetType.isDateType()) {
|
||||
return new StringLiteral(getStringValue()).convertToDate(targetType);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public static LiteralExpr createInfinity(Type type, boolean isMax) throws AnalysisException {
|
||||
Preconditions.checkArgument(!type.equals(Type.INVALID));
|
||||
if (isMax) {
|
||||
|
||||
@ -25,6 +25,7 @@ import org.apache.doris.thrift.TExprNodeType;
|
||||
import org.apache.doris.thrift.TTypeDesc;
|
||||
import org.apache.doris.thrift.TTypeNode;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.DataInput;
|
||||
@ -65,17 +66,22 @@ public class MapLiteral extends LiteralExpr {
|
||||
throw new AnalysisException("Invalid value type in Map.");
|
||||
}
|
||||
|
||||
for (int idx = 0; idx < exprs.length && idx + 1 < exprs.length; idx += 2) {
|
||||
if (exprs[idx].getType().equals(keyType)) {
|
||||
children.add(exprs[idx]);
|
||||
} else {
|
||||
children.add(exprs[idx].castTo(keyType));
|
||||
}
|
||||
if (exprs[idx + 1].getType().equals(valueType)) {
|
||||
children.add(exprs[idx + 1]);
|
||||
} else {
|
||||
children.add(exprs[idx + 1].castTo(valueType));
|
||||
try {
|
||||
for (int idx = 0; idx < exprs.length && idx + 1 < exprs.length; idx += 2) {
|
||||
if (exprs[idx].getType().equals(keyType)) {
|
||||
children.add(exprs[idx]);
|
||||
} else {
|
||||
children.add(exprs[idx].convertTo(keyType));
|
||||
}
|
||||
if (exprs[idx + 1].getType().equals(valueType)) {
|
||||
children.add(exprs[idx + 1]);
|
||||
} else {
|
||||
children.add(exprs[idx + 1].convertTo(valueType));
|
||||
}
|
||||
}
|
||||
} catch (AnalysisException e) {
|
||||
String s = "{" + StringUtils.join(exprs, ',') + "}";
|
||||
throw new AnalysisException("Invalid Map " + s + " literal: " + e.getMessage());
|
||||
}
|
||||
|
||||
type = new MapType(keyType, valueType);
|
||||
@ -85,6 +91,19 @@ public class MapLiteral extends LiteralExpr {
|
||||
super(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiteralExpr convertTo(Type targetType) throws AnalysisException {
|
||||
Preconditions.checkState(targetType instanceof MapType);
|
||||
Type keyType = ((MapType) targetType).getKeyType();
|
||||
Type valType = ((MapType) targetType).getValueType();
|
||||
LiteralExpr[] literals = new LiteralExpr[children.size()];
|
||||
for (int i = 0; i < children.size(); i += 2) {
|
||||
literals[i] = (LiteralExpr) Expr.convertLiteral(children.get(i), keyType);
|
||||
literals[i + 1] = (LiteralExpr) Expr.convertLiteral(children.get(i + 1), valType);
|
||||
}
|
||||
return new MapLiteral(literals);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expr uncheckedCastTo(Type targetType) throws AnalysisException {
|
||||
if (!targetType.isMapType()) {
|
||||
@ -95,8 +114,15 @@ public class MapLiteral extends LiteralExpr {
|
||||
Type valueType = ((MapType) targetType).getValueType();
|
||||
|
||||
for (int i = 0; i < children.size() && i + 1 < children.size(); i += 2) {
|
||||
literal.children.set(i, children.get(i).uncheckedCastTo(keyType));
|
||||
literal.children.set(i + 1, children.get(i + 1).uncheckedCastTo(valueType));
|
||||
Expr key = Expr.convertLiteral(children.get(i), keyType);
|
||||
Expr value = Expr.convertLiteral(children.get(i + 1), valueType);
|
||||
// all children should be literal or else it will make be core
|
||||
if ((!key.isLiteral()) || (!value.isLiteral())) {
|
||||
throw new AnalysisException("Unexpected map literal cast failed. from type: "
|
||||
+ this.type + ", to type: " + targetType);
|
||||
}
|
||||
literal.children.set(i, key);
|
||||
literal.children.set(i + 1, value);
|
||||
}
|
||||
literal.setType(targetType);
|
||||
return literal;
|
||||
@ -109,6 +135,20 @@ public class MapLiteral extends LiteralExpr {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStringValue() {
|
||||
List<String> list = new ArrayList<>(children.size());
|
||||
for (int i = 0; i < children.size() && i + 1 < children.size(); i += 2) {
|
||||
list.add(children.get(i).getStringValue() + ":" + children.get(i + 1).getStringValue());
|
||||
}
|
||||
return "{" + StringUtils.join(list, ", ") + "}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStringValueForArray() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String toSqlImpl() {
|
||||
List<String> list = new ArrayList<>(children.size());
|
||||
@ -166,14 +206,4 @@ public class MapLiteral extends LiteralExpr {
|
||||
Expr.writeTo(e, out);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStringValue() {
|
||||
return toSqlImpl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStringValueForArray() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,6 +24,7 @@ import org.apache.doris.common.AnalysisException;
|
||||
import org.apache.doris.thrift.TExprNode;
|
||||
import org.apache.doris.thrift.TExprNodeType;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.DataInput;
|
||||
@ -126,6 +127,17 @@ public class StructLiteral extends LiteralExpr {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiteralExpr convertTo(Type targetType) throws AnalysisException {
|
||||
Preconditions.checkState(targetType instanceof StructType);
|
||||
List<StructField> fields = ((StructType) targetType).getFields();
|
||||
LiteralExpr[] literals = new LiteralExpr[children.size()];
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
literals[i] = (LiteralExpr) Expr.convertLiteral(children.get(i), fields.get(i).getType());
|
||||
}
|
||||
return new StructLiteral(literals);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expr uncheckedCastTo(Type targetType) throws AnalysisException {
|
||||
if (!targetType.isStructType()) {
|
||||
@ -134,8 +146,13 @@ public class StructLiteral extends LiteralExpr {
|
||||
ArrayList<StructField> fields = ((StructType) targetType).getFields();
|
||||
StructLiteral literal = new StructLiteral(this);
|
||||
for (int i = 0; i < children.size(); ++ i) {
|
||||
Expr child = children.get(i);
|
||||
literal.children.set(i, child.uncheckedCastTo((fields.get(i).getType())));
|
||||
Expr child = Expr.convertLiteral(children.get(i), fields.get(i).getType());
|
||||
// all children should be literal or else it will make be core
|
||||
if (!child.isLiteral()) {
|
||||
throw new AnalysisException("Unexpected struct literal cast failed. from type: "
|
||||
+ this.type + ", to type: " + targetType);
|
||||
}
|
||||
literal.children.set(i, child);
|
||||
}
|
||||
literal.setType(targetType);
|
||||
return literal;
|
||||
|
||||
Reference in New Issue
Block a user