This is an automated email from the ASF dual-hosted git repository. morrysnow pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push: new ae428c29e2 [feature](planner)(nereids) support user defined variable (#20334) ae428c29e2 is described below commit ae428c29e23b6df7822e943d70ad7acd291412b9 Author: Chengpeng Yan <41809508+reminisc...@users.noreply.github.com> AuthorDate: Tue Jun 6 14:35:16 2023 +0800 [feature](planner)(nereids) support user defined variable (#20334) Support user-defined variables. After this PR, we can use `set @a = xx` to define a user variable and use it in the query like `select @a`. the changes of this PR: 1. Support the grammar for `set user variable` in the parser. 2. Add the `userVars` in `VariableMgr` to store the user-defined variables. 3. For the `set @a = xx`, we will store the variable name and its value in the `userVars` in `VariableMgr`. 4. For the `select @a`, we will get the value for the variable name in `userVars`. --- .../antlr4/org/apache/doris/nereids/DorisParser.g4 | 2 +- fe/fe-core/src/main/cup/sql_parser.cup | 12 ++-- .../main/java/org/apache/doris/analysis/Expr.java | 3 +- .../apache/doris/analysis/ExpressionFunctions.java | 6 +- .../java/org/apache/doris/analysis/SetType.java | 3 +- .../{SetType.java => SetUserDefinedVar.java} | 49 ++++--------- .../java/org/apache/doris/analysis/SetVar.java | 37 ++++++++-- .../{SysVariableDesc.java => VariableExpr.java} | 66 ++++++++++++------ .../doris/nereids/parser/LogicalPlanBuilder.java | 3 +- .../nereids/trees/expressions/literal/Literal.java | 7 ++ .../main/java/org/apache/doris/qe/SetExecutor.java | 3 + .../main/java/org/apache/doris/qe/VariableMgr.java | 80 ++++++++++++++++++++-- .../apache/doris/rewrite/FoldConstantsRule.java | 14 ++-- .../java/org/apache/doris/analysis/SetVarTest.java | 2 +- ...VariableDescTest.java => VariableExprTest.java} | 6 +- .../java/org/apache/doris/qe/VariableMgrTest.java | 4 +- regression-test/data/nereids_p0/test_user_var.out | 16 +++++ .../data/query_p0/set/test_user_var.out | 16 +++++ .../suites/nereids_p0/test_user_var.groovy | 32 +++++++++ .../suites/query_p0/set/test_user_var.groovy | 30 ++++++++ 20 files changed, 299 insertions(+), 92 deletions(-) diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 index 14ad9c35c4..c8035e716e 100644 --- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 +++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 @@ -342,7 +342,7 @@ primaryExpression (COMMA arguments+=expression)* (ORDER BY sortItem (COMMA sortItem)*)?)? RIGHT_PAREN (OVER windowSpec)? #functionCall | LEFT_PAREN query RIGHT_PAREN #subqueryExpression - | ATSIGN identifier #userVariable + | ATSIGN identifierOrText #userVariable | DOUBLEATSIGN (kind=(GLOBAL | SESSION) DOT)? identifier #systemVariable | identifier #columnReference | base=primaryExpression DOT fieldName=identifier #dereference diff --git a/fe/fe-core/src/main/cup/sql_parser.cup b/fe/fe-core/src/main/cup/sql_parser.cup index 3a85b99dd4..4f2014b001 100644 --- a/fe/fe-core/src/main/cup/sql_parser.cup +++ b/fe/fe-core/src/main/cup/sql_parser.cup @@ -4914,9 +4914,9 @@ option_value_no_option_type ::= {: RESULT = new SetVar(variable, expr); :} - | AT ident_or_text:var equal literal:expr + | AT ident_or_text:var equal expr:expr {: - RESULT = new SetVar(var, expr); + RESULT = new SetUserDefinedVar(var, expr); :} /* Ident */ | AT AT variable_name:variable equal set_expr_or_default:expr @@ -6398,13 +6398,17 @@ exists_predicate ::= non_pred_expr ::= sign_chain_expr:e {: RESULT = e; :} + | AT ident:l + {: + RESULT = new VariableExpr(l, SetType.USER); + :} | AT AT ident:l {: - RESULT = new SysVariableDesc(l); + RESULT = new VariableExpr(l); :} | AT AT var_ident_type:type ident:l {: - RESULT = new SysVariableDesc(l, type); + RESULT = new VariableExpr(l, type); :} | literal:l {: RESULT = l; :} diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/Expr.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/Expr.java index a6cc659794..8633b868eb 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/Expr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/Expr.java @@ -990,7 +990,8 @@ public abstract class Expr extends TreeNode<Expr> implements ParseNode, Cloneabl // Hack to ensure BE never sees TYPE_NULL. If an expr makes it this far without // being cast to a non-NULL type, the type doesn't matter and we can cast it // arbitrarily. - Preconditions.checkState(this instanceof NullLiteral || this instanceof SlotRef); + Preconditions.checkState(this instanceof NullLiteral || this instanceof SlotRef + || this instanceof VariableExpr); return NullLiteral.create(ScalarType.BOOLEAN).treeToThrift(); } TExpr result = new TExpr(); diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/ExpressionFunctions.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/ExpressionFunctions.java index e7dae9617b..e39748b570 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/ExpressionFunctions.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ExpressionFunctions.java @@ -58,7 +58,7 @@ public enum ExpressionFunctions { public Expr evalExpr(Expr constExpr) { // Function's arg are all LiteralExpr. for (Expr child : constExpr.getChildren()) { - if (!(child instanceof LiteralExpr) && !(child instanceof SysVariableDesc)) { + if (!(child instanceof LiteralExpr) && !(child instanceof VariableExpr)) { return constExpr; } } @@ -115,8 +115,8 @@ public enum ExpressionFunctions { return constExpr; } } - } else if (constExpr instanceof SysVariableDesc) { - return ((SysVariableDesc) constExpr).getLiteralExpr(); + } else if (constExpr instanceof VariableExpr) { + return ((VariableExpr) constExpr).getLiteralExpr(); } return constExpr; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/SetType.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/SetType.java index 924c1f38a9..ae0fbd27bc 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/SetType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/SetType.java @@ -23,7 +23,8 @@ import org.apache.doris.thrift.TVarType; public enum SetType { DEFAULT("DEFAULT"), GLOBAL("GLOBAL"), - SESSION("SESSION"); + SESSION("SESSION"), + USER("USER"); private String desc; diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/SetType.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/SetUserDefinedVar.java similarity index 53% copy from fe/fe-core/src/main/java/org/apache/doris/analysis/SetType.java copy to fe/fe-core/src/main/java/org/apache/doris/analysis/SetUserDefinedVar.java index 924c1f38a9..7b0c5d98aa 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/SetType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/SetUserDefinedVar.java @@ -17,44 +17,23 @@ package org.apache.doris.analysis; -import org.apache.doris.thrift.TVarType; +import org.apache.doris.catalog.ScalarType; +import org.apache.doris.common.AnalysisException; -// Set statement type. -public enum SetType { - DEFAULT("DEFAULT"), - GLOBAL("GLOBAL"), - SESSION("SESSION"); - - private String desc; - - SetType(String desc) { - this.desc = desc; - } - - public TVarType toThrift() { - switch (this) { - case GLOBAL: - return TVarType.GLOBAL; - default: - return TVarType.SESSION; - } - } - - public static SetType fromThrift(TVarType tType) { - switch (tType) { - case GLOBAL: - return SetType.GLOBAL; - default: - return SetType.SESSION; - } - } - - public String toSql() { - return desc; +public class SetUserDefinedVar extends SetVar { + public SetUserDefinedVar(String variable, Expr value) { + super(SetType.USER, variable, value, SetVarType.SET_USER_DEFINED_VAR); } @Override - public String toString() { - return toSql(); + public void analyze(Analyzer analyzer) throws AnalysisException { + Expr expression = getValue(); + if (expression instanceof NullLiteral) { + setResult(NullLiteral.create(ScalarType.NULL)); + } else if (expression instanceof LiteralExpr) { + setResult((LiteralExpr) expression); + } else { + throw new AnalysisException("Unsupported to set the non-literal for user defined variables."); + } } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/SetVar.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/SetVar.java index ccb505bbe4..8afa942dba 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/SetVar.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/SetVar.java @@ -43,7 +43,8 @@ public class SetVar { SET_LDAP_PASS_VAR, SET_NAMES_VAR, SET_TRANSACTION, - SET_USER_PROPERTY_VAR + SET_USER_PROPERTY_VAR, + SET_USER_DEFINED_VAR, } private String variable; @@ -75,14 +76,36 @@ public class SetVar { } } + public SetVar(SetType setType, String variable, Expr value, SetVarType varType) { + this.type = setType; + this.varType = varType; + this.variable = variable; + this.value = value; + if (value instanceof LiteralExpr) { + this.result = (LiteralExpr) value; + } + } + public String getVariable() { return variable; } - public LiteralExpr getValue() { + public Expr getValue() { + return value; + } + + public void setValue(Expr value) { + this.value = value; + } + + public LiteralExpr getResult() { return result; } + public void setResult(LiteralExpr result) { + this.result = result; + } + public SetType getType() { return type; } @@ -144,7 +167,7 @@ public class SetVar { } if (getVariable().equalsIgnoreCase(SessionVariable.PREFER_JOIN_METHOD)) { - String value = getValue().getStringValue(); + String value = getResult().getStringValue(); if (!value.equalsIgnoreCase("broadcast") && !value.equalsIgnoreCase("shuffle")) { ErrorReport.reportAnalysisException(ErrorCode.ERR_WRONG_VALUE_FOR_VAR, SessionVariable.PREFER_JOIN_METHOD, value); @@ -153,11 +176,11 @@ public class SetVar { // Check variable time_zone value is valid if (getVariable().equalsIgnoreCase(SessionVariable.TIME_ZONE)) { - this.value = new StringLiteral(TimeUtils.checkTimeZoneValidAndStandardize(getValue().getStringValue())); + this.value = new StringLiteral(TimeUtils.checkTimeZoneValidAndStandardize(getResult().getStringValue())); this.result = (LiteralExpr) this.value; } if (getVariable().equalsIgnoreCase(SessionVariable.PARALLEL_FRAGMENT_EXEC_INSTANCE_NUM)) { - int instanceNum = Integer.parseInt(getValue().getStringValue()); + int instanceNum = Integer.parseInt(getResult().getStringValue()); if (instanceNum > Config.max_instance_num) { ErrorReport.reportAnalysisException(ErrorCode.ERR_WRONG_VALUE_FOR_VAR, SessionVariable.PARALLEL_FRAGMENT_EXEC_INSTANCE_NUM, @@ -165,11 +188,11 @@ public class SetVar { } } if (getVariable().equalsIgnoreCase(SessionVariable.EXEC_MEM_LIMIT)) { - this.value = new StringLiteral(Long.toString(ParseUtil.analyzeDataVolumn(getValue().getStringValue()))); + this.value = new StringLiteral(Long.toString(ParseUtil.analyzeDataVolumn(getResult().getStringValue()))); this.result = (LiteralExpr) this.value; } if (getVariable().equalsIgnoreCase(SessionVariable.SCAN_QUEUE_MEM_LIMIT)) { - this.value = new StringLiteral(Long.toString(ParseUtil.analyzeDataVolumn(getValue().getStringValue()))); + this.value = new StringLiteral(Long.toString(ParseUtil.analyzeDataVolumn(getResult().getStringValue()))); this.result = (LiteralExpr) this.value; } if (getVariable().equalsIgnoreCase("is_report_success")) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/SysVariableDesc.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/VariableExpr.java similarity index 74% rename from fe/fe-core/src/main/java/org/apache/doris/analysis/SysVariableDesc.java rename to fe/fe-core/src/main/java/org/apache/doris/analysis/VariableExpr.java index 023be528e6..649bb4017f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/SysVariableDesc.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/VariableExpr.java @@ -32,33 +32,37 @@ import org.apache.doris.thrift.TStringLiteral; import com.google.common.base.Strings; +import java.math.BigDecimal; import java.util.Objects; -// System variable +// Variable expr: including the system variable and user define variable. // Converted to StringLiteral in analyze, if this variable is not exist, throw AnalysisException. -public class SysVariableDesc extends Expr { +public class VariableExpr extends Expr { private String name; private SetType setType; + private boolean isNull; private boolean boolValue; private long intValue; private double floatValue; + private BigDecimal decimalValue; private String strValue; private LiteralExpr literalExpr; - public SysVariableDesc(String name) { + public VariableExpr(String name) { this(name, SetType.SESSION); } - public SysVariableDesc(String name, SetType setType) { + public VariableExpr(String name, SetType setType) { this.name = name; this.setType = setType; } - protected SysVariableDesc(SysVariableDesc other) { + protected VariableExpr(VariableExpr other) { super(other); name = other.name; setType = other.setType; + isNull = other.isNull; boolValue = other.boolValue; intValue = other.intValue; floatValue = other.floatValue; @@ -67,18 +71,22 @@ public class SysVariableDesc extends Expr { @Override public Expr clone() { - return new SysVariableDesc(this); + return new VariableExpr(this); } @Override public void analyzeImpl(Analyzer analyzer) throws AnalysisException { - VariableMgr.fillValue(analyzer.getContext().getSessionVariable(), this); - if (!Strings.isNullOrEmpty(name) && VariableVarConverters.hasConverter(name)) { - setType(Type.VARCHAR); - try { - setStringValue(VariableVarConverters.decode(name, intValue)); - } catch (DdlException e) { - ErrorReport.reportAnalysisException(e.getMessage()); + if (setType == SetType.USER) { + VariableMgr.fillValueForUserDefinedVar(this); + } else { + VariableMgr.fillValue(analyzer.getContext().getSessionVariable(), this); + if (!Strings.isNullOrEmpty(name) && VariableVarConverters.hasConverter(name)) { + setType(Type.VARCHAR); + try { + setStringValue(VariableVarConverters.decode(name, intValue)); + } catch (DdlException e) { + ErrorReport.reportAnalysisException(e.getMessage()); + } } } } @@ -91,6 +99,14 @@ public class SysVariableDesc extends Expr { return setType; } + public void setIsNull() { + isNull = true; + } + + public boolean isNull() { + return isNull; + } + public void setBoolValue(boolean value) { this.boolValue = value; this.literalExpr = new BoolLiteral(value); @@ -106,6 +122,11 @@ public class SysVariableDesc extends Expr { this.literalExpr = new FloatLiteral(value); } + public void setDecimalValue(BigDecimal value) { + this.decimalValue = value; + this.literalExpr = new DecimalLiteral(value); + } + public void setStringValue(String value) { this.strValue = value; this.literalExpr = new StringLiteral(value); @@ -164,9 +185,14 @@ public class SysVariableDesc extends Expr { @Override public String toSqlImpl() { - StringBuilder sb = new StringBuilder("@@"); - if (setType == SetType.GLOBAL) { - sb.append("GLOBAL."); + StringBuilder sb = new StringBuilder(); + if (setType == SetType.USER) { + sb.append("@"); + } else { + sb.append("@@"); + if (setType == SetType.GLOBAL) { + sb.append("GLOBAL."); + } } sb.append(name); return sb.toString(); @@ -182,16 +208,16 @@ public class SysVariableDesc extends Expr { if (this == obj) { return true; } - if (!(obj instanceof SysVariableDesc)) { + if (!(obj instanceof VariableExpr)) { return false; } - if (!name.equals(((SysVariableDesc) obj).getName())) { + if (!name.equals(((VariableExpr) obj).getName())) { return false; } - if (!setType.equals(((SysVariableDesc) obj).getSetType())) { + if (!setType.equals(((VariableExpr) obj).getSetType())) { return false; } - return Objects.equals(literalExpr, ((SysVariableDesc) obj).getLiteralExpr()); + return Objects.equals(literalExpr, ((VariableExpr) obj).getLiteralExpr()); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java index 491b1e80f6..08f1ae00fb 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java @@ -633,7 +633,8 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> { @Override public Expression visitUserVariable(UserVariableContext ctx) { - throw new ParseException("Unsupported user variable :" + ctx.getText(), ctx); + String name = ctx.identifierOrText().getText(); + return VariableMgr.getLiteralForUserVar(name); } /** diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java index 109357499f..123aa618f4 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java @@ -19,6 +19,7 @@ package org.apache.doris.nereids.trees.expressions.literal; import org.apache.doris.analysis.LiteralExpr; import org.apache.doris.catalog.Type; +import org.apache.doris.common.Config; import org.apache.doris.nereids.exceptions.AnalysisException; import org.apache.doris.nereids.exceptions.UnboundException; import org.apache.doris.nereids.trees.expressions.Expression; @@ -75,6 +76,12 @@ public abstract class Literal extends Expression implements LeafExpression, Comp return new FloatLiteral((Float) value); } else if (value instanceof Double) { return new DoubleLiteral((Double) value); + } else if (value instanceof BigDecimal) { + if (Config.enable_decimal_conversion) { + return new DecimalV3Literal((BigDecimal) value); + } else { + return new DecimalLiteral((BigDecimal) value); + } } else if (value instanceof Boolean) { return BooleanLiteral.of((Boolean) value); } else if (value instanceof String) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/SetExecutor.java b/fe/fe-core/src/main/java/org/apache/doris/qe/SetExecutor.java index c88e7e3336..9dbe9ca8a9 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/SetExecutor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/SetExecutor.java @@ -22,6 +22,7 @@ import org.apache.doris.analysis.SetNamesVar; import org.apache.doris.analysis.SetPassVar; import org.apache.doris.analysis.SetStmt; import org.apache.doris.analysis.SetTransaction; +import org.apache.doris.analysis.SetUserDefinedVar; import org.apache.doris.analysis.SetVar; import org.apache.doris.common.DdlException; @@ -54,6 +55,8 @@ public class SetExecutor { } else if (var instanceof SetTransaction) { // do nothing return; + } else if (var instanceof SetUserDefinedVar) { + VariableMgr.setUserVar(var); } else { VariableMgr.setVar(ctx.getSessionVariable(), var); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/VariableMgr.java b/fe/fe-core/src/main/java/org/apache/doris/qe/VariableMgr.java index 5408e74071..24b7468e77 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/VariableMgr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/VariableMgr.java @@ -17,9 +17,16 @@ package org.apache.doris.qe; +import org.apache.doris.analysis.BoolLiteral; +import org.apache.doris.analysis.DecimalLiteral; +import org.apache.doris.analysis.FloatLiteral; +import org.apache.doris.analysis.IntLiteral; +import org.apache.doris.analysis.LiteralExpr; +import org.apache.doris.analysis.NullLiteral; import org.apache.doris.analysis.SetType; import org.apache.doris.analysis.SetVar; -import org.apache.doris.analysis.SysVariableDesc; +import org.apache.doris.analysis.StringLiteral; +import org.apache.doris.analysis.VariableExpr; import org.apache.doris.catalog.Env; import org.apache.doris.catalog.Type; import org.apache.doris.common.AnalysisException; @@ -52,6 +59,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Field; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.locks.Lock; @@ -116,6 +124,8 @@ public class VariableMgr { // its display name is "experimental_foo" private static ImmutableMap<String, VarContext> ctxByDisplayVarName; + private static Map<String, LiteralExpr> userVars = new HashMap<String, LiteralExpr>(); + // This variable is equivalent to the default value of session variables. // Whenever a new session is established, the value in this object is copied to the session-level variable. private static SessionVariable defaultSessionVariable; @@ -258,6 +268,10 @@ public class VariableMgr { } } + public static void setUserVar(SetVar setVar) { + userVars.put(setVar.getVariable(), setVar.getResult()); + } + // Entry of handling SetVarStmt // Input: // sessionVariable: the variable of current session @@ -314,8 +328,8 @@ public class VariableMgr { VarAttr attr = ctx.getField().getAnnotation(VarAttr.class); String value; // If value is null, this is `set variable = DEFAULT` - if (setVar.getValue() != null) { - value = setVar.getValue().getStringValue(); + if (setVar.getResult() != null) { + value = setVar.getResult().getStringValue(); } else { value = ctx.getDefaultValue(); if (value == null) { @@ -416,7 +430,7 @@ public class VariableMgr { } // Get variable value through variable name, used to satisfy statement like `SELECT @@comment_version` - public static void fillValue(SessionVariable var, SysVariableDesc desc) throws AnalysisException { + public static void fillValue(SessionVariable var, VariableExpr desc) throws AnalysisException { VarContext ctx = ctxByVarName.get(desc.getName()); if (ctx == null) { ErrorReport.reportAnalysisException(ErrorCode.ERR_UNKNOWN_SYSTEM_VARIABLE, desc.getName()); @@ -434,7 +448,7 @@ public class VariableMgr { } } - private static void fillValue(Object obj, Field field, SysVariableDesc desc) { + private static void fillValue(Object obj, Field field, VariableExpr desc) { try { switch (field.getType().getSimpleName()) { case "boolean": @@ -479,6 +493,36 @@ public class VariableMgr { } } + // Get variable value through variable name, used to satisfy statement like `SELECT @@comment_version` + public static void fillValueForUserDefinedVar(VariableExpr desc) { + String varName = desc.getName(); + if (userVars.containsKey(varName)) { + LiteralExpr literalExpr = userVars.get(varName); + desc.setType(literalExpr.getType()); + if (literalExpr instanceof BoolLiteral) { + desc.setBoolValue(((BoolLiteral) literalExpr).getValue()); + } else if (literalExpr instanceof IntLiteral) { + desc.setIntValue(((IntLiteral) literalExpr).getValue()); + } else if (literalExpr instanceof FloatLiteral) { + desc.setFloatValue(((FloatLiteral) literalExpr).getValue()); + } else if (literalExpr instanceof DecimalLiteral) { + desc.setDecimalValue(((DecimalLiteral) literalExpr).getValue()); + } else if (literalExpr instanceof StringLiteral) { + desc.setStringValue(((StringLiteral) literalExpr).getValue()); + } else if (literalExpr instanceof NullLiteral) { + desc.setType(Type.NULL); + desc.setIsNull(); + } else { + desc.setType(Type.VARCHAR); + desc.setStringValue(""); + } + } else { + // If there are no such user defined var, just fill the NULL value. + desc.setType(Type.NULL); + desc.setIsNull(); + } + } + private static String getValue(SessionVariable var, String name, SetType setType) throws AnalysisException { VarContext ctx = ctxByVarName.get(name); if (ctx == null) { @@ -499,7 +543,7 @@ public class VariableMgr { // Get variable value through variable name, used to satisfy statement like `SELECT @@comment_version` // For test only - public static String getValue(SessionVariable var, SysVariableDesc desc) throws AnalysisException { + public static String getValue(SessionVariable var, VariableExpr desc) throws AnalysisException { return getValue(var, desc.getName(), desc.getSetType()); } @@ -550,6 +594,30 @@ public class VariableMgr { return Literal.of(""); } + public static @Nullable Literal getLiteralForUserVar(String varName) { + if (userVars.containsKey(varName)) { + LiteralExpr literalExpr = userVars.get(varName); + if (literalExpr instanceof BoolLiteral) { + return Literal.of(((BoolLiteral) literalExpr).getValue()); + } else if (literalExpr instanceof IntLiteral) { + return Literal.of(((IntLiteral) literalExpr).getValue()); + } else if (literalExpr instanceof FloatLiteral) { + return Literal.of(((FloatLiteral) literalExpr).getValue()); + } else if (literalExpr instanceof DecimalLiteral) { + return Literal.of(((DecimalLiteral) literalExpr).getValue()); + } else if (literalExpr instanceof StringLiteral) { + return Literal.of(((StringLiteral) literalExpr).getValue()); + } else if (literalExpr instanceof NullLiteral) { + return Literal.of(null); + } else { + return Literal.of(""); + } + } else { + // If there are no such user defined var, just return the NULL value. + return Literal.of(null); + } + } + private static String getValue(Object obj, Field field) { try { switch (field.getType().getSimpleName()) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/rewrite/FoldConstantsRule.java b/fe/fe-core/src/main/java/org/apache/doris/rewrite/FoldConstantsRule.java index a4baf0ca3e..dcc0bede70 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/rewrite/FoldConstantsRule.java +++ b/fe/fe-core/src/main/java/org/apache/doris/rewrite/FoldConstantsRule.java @@ -29,7 +29,7 @@ import org.apache.doris.analysis.Expr; import org.apache.doris.analysis.InformationFunction; import org.apache.doris.analysis.LiteralExpr; import org.apache.doris.analysis.NullLiteral; -import org.apache.doris.analysis.SysVariableDesc; +import org.apache.doris.analysis.VariableExpr; import org.apache.doris.catalog.Env; import org.apache.doris.catalog.PrimitiveType; import org.apache.doris.catalog.ScalarType; @@ -216,7 +216,7 @@ public class FoldConstantsRule implements ExprRewriteRule { return; } // collect sysVariableDesc expr - if (expr.contains(Predicates.instanceOf(SysVariableDesc.class))) { + if (expr.contains(Predicates.instanceOf(VariableExpr.class))) { getSysVarDescExpr(expr, sysVarMap); return; } @@ -244,14 +244,14 @@ public class FoldConstantsRule implements ExprRewriteRule { } private void getSysVarDescExpr(Expr expr, Map<String, Expr> sysVarMap) { - if (expr instanceof SysVariableDesc) { - Expr literalExpr = ((SysVariableDesc) expr).getLiteralExpr(); + if (expr instanceof VariableExpr) { + Expr literalExpr = ((VariableExpr) expr).getLiteralExpr(); if (literalExpr == null) { try { - VariableMgr.fillValue(ConnectContext.get().getSessionVariable(), (SysVariableDesc) expr); - literalExpr = ((SysVariableDesc) expr).getLiteralExpr(); + VariableMgr.fillValue(ConnectContext.get().getSessionVariable(), (VariableExpr) expr); + literalExpr = ((VariableExpr) expr).getLiteralExpr(); } catch (AnalysisException e) { - LOG.warn("failed to get session variable value: " + ((SysVariableDesc) expr).getName()); + LOG.warn("failed to get session variable value: " + ((VariableExpr) expr).getName()); } } sysVarMap.put(expr.getId().toString(), literalExpr); diff --git a/fe/fe-core/src/test/java/org/apache/doris/analysis/SetVarTest.java b/fe/fe-core/src/test/java/org/apache/doris/analysis/SetVarTest.java index 7b5360c87c..d88538a9a5 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/analysis/SetVarTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/analysis/SetVarTest.java @@ -52,7 +52,7 @@ public class SetVarTest { var.setType(SetType.GLOBAL); Assert.assertEquals(SetType.GLOBAL, var.getType()); Assert.assertEquals("names", var.getVariable()); - Assert.assertEquals("utf-8", var.getValue().getStringValue()); + Assert.assertEquals("utf-8", var.getResult().getStringValue()); Assert.assertEquals("GLOBAL names = 'utf-8'", var.toString()); diff --git a/fe/fe-core/src/test/java/org/apache/doris/analysis/SysVariableDescTest.java b/fe/fe-core/src/test/java/org/apache/doris/analysis/VariableExprTest.java similarity index 92% rename from fe/fe-core/src/test/java/org/apache/doris/analysis/SysVariableDescTest.java rename to fe/fe-core/src/test/java/org/apache/doris/analysis/VariableExprTest.java index fcc8b8ddf2..28334f4102 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/analysis/SysVariableDescTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/analysis/VariableExprTest.java @@ -26,11 +26,11 @@ import org.apache.doris.thrift.TExprNodeType; import org.junit.Assert; import org.junit.Test; -public class SysVariableDescTest { +public class VariableExprTest { @Test public void testNormal() throws AnalysisException { - SysVariableDesc desc = new SysVariableDesc("version_comment"); + VariableExpr desc = new VariableExpr("version_comment"); desc.analyze(AccessTestUtil.fetchAdminAnalyzer(false)); Assert.assertEquals("@@version_comment", desc.toSql()); Assert.assertEquals("version_comment", desc.getName()); @@ -45,7 +45,7 @@ public class SysVariableDescTest { @Test(expected = AnalysisException.class) public void testNoVar() throws AnalysisException { - SysVariableDesc desc = new SysVariableDesc("zcPrivate"); + VariableExpr desc = new VariableExpr("zcPrivate"); desc.analyze(AccessTestUtil.fetchAdminAnalyzer(false)); Assert.fail("No exception throws."); } diff --git a/fe/fe-core/src/test/java/org/apache/doris/qe/VariableMgrTest.java b/fe/fe-core/src/test/java/org/apache/doris/qe/VariableMgrTest.java index b8abd92d32..f1b8e7b5a7 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/qe/VariableMgrTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/qe/VariableMgrTest.java @@ -22,7 +22,7 @@ import org.apache.doris.analysis.SetStmt; import org.apache.doris.analysis.SetType; import org.apache.doris.analysis.SetVar; import org.apache.doris.analysis.StringLiteral; -import org.apache.doris.analysis.SysVariableDesc; +import org.apache.doris.analysis.VariableExpr; import org.apache.doris.catalog.Env; import org.apache.doris.common.Config; import org.apache.doris.common.DdlException; @@ -154,7 +154,7 @@ public class VariableMgrTest { Assert.assertEquals(8L, ctx.getSessionVariable().getRuntimeFilterType()); // Get from name - SysVariableDesc desc = new SysVariableDesc("exec_mem_limit"); + VariableExpr desc = new VariableExpr("exec_mem_limit"); Assert.assertEquals(var.getMaxExecMemByte() + "", VariableMgr.getValue(var, desc)); } diff --git a/regression-test/data/nereids_p0/test_user_var.out b/regression-test/data/nereids_p0/test_user_var.out new file mode 100644 index 0000000000..41aebfe022 --- /dev/null +++ b/regression-test/data/nereids_p0/test_user_var.out @@ -0,0 +1,16 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !select1 -- +1 0 -1 + +-- !select2 -- +1.1 0.0 -1.1 + +-- !select3 -- +H + +-- !select4 -- +true false + +-- !select5 -- +\N \N + diff --git a/regression-test/data/query_p0/set/test_user_var.out b/regression-test/data/query_p0/set/test_user_var.out new file mode 100644 index 0000000000..41aebfe022 --- /dev/null +++ b/regression-test/data/query_p0/set/test_user_var.out @@ -0,0 +1,16 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !select1 -- +1 0 -1 + +-- !select2 -- +1.1 0.0 -1.1 + +-- !select3 -- +H + +-- !select4 -- +true false + +-- !select5 -- +\N \N + diff --git a/regression-test/suites/nereids_p0/test_user_var.groovy b/regression-test/suites/nereids_p0/test_user_var.groovy new file mode 100644 index 0000000000..f54e139632 --- /dev/null +++ b/regression-test/suites/nereids_p0/test_user_var.groovy @@ -0,0 +1,32 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +suite("test_user_var") { + sql "SET enable_nereids_planner=true" + sql "SET enable_fallback_to_original_planner=false" + sql "SET @a1=1, @a2=0, @a3=-1" + sql "SET @b1=1.1, @b2=0.0, @b3=-1.1" + sql "SET @c1='H', @c2=''" + sql "SET @d1=true, @d2=false" + sql "SET @f1=null" + + qt_select1 'select @a1, @a2, @a3;' + qt_select2 'select @b1, @b2, @b3;' + qt_select3 'select @c1, @c2;' + qt_select4 'select @d1, @d2;' + qt_select5 'select @f1, @f2;' +} \ No newline at end of file diff --git a/regression-test/suites/query_p0/set/test_user_var.groovy b/regression-test/suites/query_p0/set/test_user_var.groovy new file mode 100644 index 0000000000..af2d2caadc --- /dev/null +++ b/regression-test/suites/query_p0/set/test_user_var.groovy @@ -0,0 +1,30 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +suite("test_user_var") { + sql "SET @a1=1, @a2=0, @a3=-1" + sql "SET @b1=1.1, @b2=0.0, @b3=-1.1" + sql "SET @c1='H', @c2=''" + sql "SET @d1=true, @d2=false" + sql "SET @f1=null" + + qt_select1 'select @a1, @a2, @a3;' + qt_select2 'select @b1, @b2, @b3;' + qt_select3 'select @c1, @c2;' + qt_select4 'select @d1, @d2;' + qt_select5 'select @f1, @f2;' +} \ No newline at end of file --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org