[Fix](Variant) support view for accessing variant subcolumns and temp… (#32225)

This commit is contained in:
lihangyu
2024-03-15 14:26:12 +08:00
committed by yiguolei
parent 9e014cfb8a
commit 5478193002
6 changed files with 203 additions and 2 deletions

View File

@ -492,17 +492,24 @@ public class BinaryPredicate extends Predicate implements Writable {
}
}
if ((t1.isDecimalV3Type() && !t2.isStringType() && !t2.isFloatingPointType())
|| (t2.isDecimalV3Type() && !t1.isStringType() && !t1.isFloatingPointType())) {
if ((t1.isDecimalV3Type() && !t2.isStringType() && !t2.isFloatingPointType() && !t2.isVariantType())
|| (t2.isDecimalV3Type() && !t1.isStringType() && !t1.isFloatingPointType() && !t1.isVariantType())) {
return Type.getAssignmentCompatibleType(getChild(0).getType(), getChild(1).getType(), false,
SessionVariable.getEnableDecimal256());
}
// Variant can be implicit cast to numeric type and string type at present
if (t1.isVariantType() && (t2.isNumericType() || t2.isStringType())) {
if (t2.isDecimalV2Type() || t2.isDecimalV3Type()) {
// TODO support decimal
return Type.DOUBLE;
}
return Type.fromPrimitiveType(t2);
}
if (t2.isVariantType() && (t1.isNumericType() || t1.isStringType())) {
if (t1.isDecimalV2Type() || t1.isDecimalV3Type()) {
return Type.DOUBLE;
}
return Type.fromPrimitiveType(t1);
}

View File

@ -114,6 +114,12 @@ public class ExpressionAnalyzer extends SubExprAnalyzer<ExpressionRewriteContext
private final boolean bindSlotInOuterScope;
private boolean currentInLambda;
// Keep track of which element_at function's level
// e.g. element_at(element_at(v, 'repo'), 'name') level 1
// element_at(v, 'repo') level 2
// Only works with function ElementAt which satisfy condition PushDownToProjectionFunction.validToPushDown
private int currentElementAtLevel = 0;
public ExpressionAnalyzer(Plan currentPlan, Scope scope, CascadesContext cascadesContext,
boolean enableExactMatch, boolean bindSlotInOuterScope) {
super(scope, cascadesContext);
@ -285,6 +291,9 @@ public class ExpressionAnalyzer extends SubExprAnalyzer<ExpressionRewriteContext
* ******************************************************************************************** */
@Override
public Expression visitUnboundFunction(UnboundFunction unboundFunction, ExpressionRewriteContext context) {
if (unboundFunction.getName().equalsIgnoreCase("element_at")) {
++currentElementAtLevel;
}
if (unboundFunction.isHighOrder()) {
unboundFunction = bindHighOrderFunction(unboundFunction, context);
} else {
@ -331,6 +340,17 @@ public class ExpressionAnalyzer extends SubExprAnalyzer<ExpressionRewriteContext
// so wrap COUNT with Nvl to ensure it's result is 0 instead of null to get the correct result
boundFunction = new Nvl(boundFunction, new BigIntLiteral(0));
}
if (currentElementAtLevel == 1
&& PushDownToProjectionFunction.validToPushDown(boundFunction)) {
// Only rewrite the top level of PushDownToProjectionFunction, otherwise invalid slot will be generated
// currentElementAtLevel == 1 means at the top of element_at function, other levels will be ignored.
currentElementAtLevel = 0;
return visitElementAt((ElementAt) boundFunction, context);
}
if (boundFunction instanceof ElementAt) {
--currentElementAtLevel;
}
return boundFunction;
}
}

View File

@ -80,6 +80,12 @@ public class FunctionBinder extends AbstractExpressionRewriteRule {
public static final FunctionBinder INSTANCE = new FunctionBinder();
// Keep track of which element_at function's level
// e.g. element_at(element_at(v, 'repo'), 'name') level 1
// element_at(v, 'repo') level 2
// Only works with function ElementAt which satisfy condition PushDownToProjectionFunction.validToPushDown
private int currentElementAtLevel = 0;
@Override
public Expression visit(Expression expr, ExpressionRewriteContext context) {
expr = super.visit(expr, context);
@ -141,6 +147,9 @@ public class FunctionBinder extends AbstractExpressionRewriteRule {
@Override
public Expression visitUnboundFunction(UnboundFunction unboundFunction, ExpressionRewriteContext context) {
if (unboundFunction.getName().equalsIgnoreCase("element_at")) {
++currentElementAtLevel;
}
if (unboundFunction.isHighOrder()) {
unboundFunction = bindHighOrderFunction(unboundFunction, context);
} else {
@ -188,6 +197,16 @@ public class FunctionBinder extends AbstractExpressionRewriteRule {
// so wrap COUNT with Nvl to ensure it's result is 0 instead of null to get the correct result
boundFunction = new Nvl(boundFunction, new BigIntLiteral(0));
}
if (currentElementAtLevel == 1
&& PushDownToProjectionFunction.validToPushDown(boundFunction)) {
// Only rewrite the top level of PushDownToProjectionFunction, otherwise invalid slot will be generated
// currentElementAtLevel == 1 means at the top of element_at function, other levels will be ignored.
currentElementAtLevel = 0;
return visitElementAt((ElementAt) boundFunction, context);
}
if (boundFunction instanceof ElementAt) {
--currentElementAtLevel;
}
return boundFunction;
}
}
@ -201,6 +220,7 @@ public class FunctionBinder extends AbstractExpressionRewriteRule {
@Override
public Expression visitElementAt(ElementAt elementAt, ExpressionRewriteContext context) {
Expression boundFunction = visitBoundFunction(elementAt, context);
if (PushDownToProjectionFunction.validToPushDown(boundFunction)) {
if (ConnectContext.get() != null
&& ConnectContext.get().getSessionVariable() != null

View File

@ -1294,9 +1294,17 @@ public class TypeCoercionUtils {
// variant type
if ((leftType.isVariantType() && (rightType.isStringLikeType() || rightType.isNumericType()))) {
if (rightType.isDecimalLikeType()) {
// TODO support decimal
return Optional.of(DoubleType.INSTANCE);
}
return Optional.of(rightType);
}
if ((rightType.isVariantType() && (leftType.isStringLikeType() || leftType.isNumericType()))) {
if (leftType.isDecimalLikeType()) {
// TODO support decimal
return Optional.of(DoubleType.INSTANCE);
}
return Optional.of(leftType);
}
return Optional.of(DoubleType.INSTANCE);