You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by mo...@apache.org on 2023/01/11 13:41:24 UTC

[doris] branch master updated: [feature](Nereids) parse pipe_concat symbol as concat when sql mode set to PIPES_AS_CONCAT (#15775)

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 88a2088c1d [feature](Nereids) parse pipe_concat symbol as concat when sql mode set to  PIPES_AS_CONCAT (#15775)
88a2088c1d is described below

commit 88a2088c1df4b075b4031343335a876f5d351400
Author: 谢健 <ji...@gmail.com>
AuthorDate: Wed Jan 11 21:41:14 2023 +0800

    [feature](Nereids) parse pipe_concat symbol as concat when sql mode set to  PIPES_AS_CONCAT (#15775)
---
 .../antlr4/org/apache/doris/nereids/DorisLexer.g4  |  2 +-
 .../antlr4/org/apache/doris/nereids/DorisParser.g4 | 13 +++---
 .../doris/nereids/parser/LogicalPlanBuilder.java   | 52 +++++++++++++++++-----
 .../rewrite/rules/FoldConstantRuleOnFE.java        | 11 -----
 .../expressions/literal/IntegerLikeLiteral.java    |  4 ++
 .../java/org/apache/doris/qe/SessionVariable.java  |  2 +-
 .../java/org/apache/doris/qe/SqlModeHelper.java    | 14 +++---
 .../main/java/org/apache/doris/qe/VariableMgr.java | 49 +++++++++++++++++---
 .../suites/nereids_syntax_p0/expression.groovy     |  6 +++
 .../suites/nereids_syntax_p0/system_var.groovy     |  2 +-
 10 files changed, 114 insertions(+), 41 deletions(-)

diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4 b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4
index 69683b982b..ae81bf6739 100644
--- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4
+++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4
@@ -416,7 +416,7 @@ TILDE: '~';
 AMPERSAND: '&';
 LOGICALAND: '&&';
 PIPE: '|';
-CONCAT_PIPE: '||';
+DOUBLEPIPES: '||';
 HAT: '^';
 COLON: ':';
 ARROW: '->';
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 40c88b27af..594b3f7a0b 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
@@ -245,13 +245,14 @@ expression
     ;
 
 booleanExpression
-    : NOT booleanExpression                                         #logicalNot
-    | EXISTS LEFT_PAREN query RIGHT_PAREN                           #exist
-    | (ISNULL | IS_NULL_PRED) LEFT_PAREN valueExpression RIGHT_PAREN        #isnull
-    | IS_NOT_NULL_PRED LEFT_PAREN valueExpression RIGHT_PAREN        #is_not_null_pred
-    | valueExpression predicate?                                    #predicated
+    : NOT booleanExpression                                                         #logicalNot
+    | EXISTS LEFT_PAREN query RIGHT_PAREN                                           #exist
+    | (ISNULL | IS_NULL_PRED) LEFT_PAREN valueExpression RIGHT_PAREN                #isnull
+    | IS_NOT_NULL_PRED LEFT_PAREN valueExpression RIGHT_PAREN                       #is_not_null_pred
+    | valueExpression predicate?                                                    #predicated
     | left=booleanExpression operator=(AND | LOGICALAND) right=booleanExpression    #logicalBinary
-    | left=booleanExpression operator=(OR | CONCAT_PIPE) right=booleanExpression    #logicalBinary
+    | left=booleanExpression operator=OR right=booleanExpression                    #logicalBinary
+    | left=booleanExpression operator=DOUBLEPIPES right=booleanExpression           #doublePipes
     ;
 
 predicate
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 1485627517..a61f62d1df 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
@@ -19,6 +19,7 @@ package org.apache.doris.nereids.parser;
 
 import org.apache.doris.analysis.ArithmeticExpr.Operator;
 import org.apache.doris.analysis.SetType;
+import org.apache.doris.common.DdlException;
 import org.apache.doris.common.Pair;
 import org.apache.doris.nereids.DorisParser;
 import org.apache.doris.nereids.DorisParser.AggClauseContext;
@@ -143,7 +144,6 @@ import org.apache.doris.nereids.trees.expressions.ScalarSubquery;
 import org.apache.doris.nereids.trees.expressions.Subtract;
 import org.apache.doris.nereids.trees.expressions.TVFProperties;
 import org.apache.doris.nereids.trees.expressions.TimestampArithmetic;
-import org.apache.doris.nereids.trees.expressions.VariableDesc;
 import org.apache.doris.nereids.trees.expressions.WhenClause;
 import org.apache.doris.nereids.trees.expressions.functions.Function;
 import org.apache.doris.nereids.trees.expressions.functions.agg.Count;
@@ -171,12 +171,14 @@ import org.apache.doris.nereids.trees.expressions.literal.BooleanLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.DateLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.DateTimeLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.DecimalLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.IntegerLikeLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.IntegerLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.Interval;
 import org.apache.doris.nereids.trees.expressions.literal.LargeIntLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.Literal;
 import org.apache.doris.nereids.trees.expressions.literal.NullLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.SmallIntLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.StringLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.TinyIntLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.VarcharLiteral;
 import org.apache.doris.nereids.trees.plans.JoinHint;
@@ -213,7 +215,13 @@ import org.apache.doris.nereids.types.TinyIntType;
 import org.apache.doris.nereids.util.ExpressionUtils;
 import org.apache.doris.policy.PolicyTypeEnum;
 import org.apache.doris.qe.ConnectContext;
+import org.apache.doris.qe.SessionVariable;
+import org.apache.doris.qe.SqlModeHelper;
+import org.apache.doris.qe.VariableMgr;
+import org.apache.doris.qe.VariableVarConverters;
 
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableMap.Builder;
@@ -527,17 +535,29 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> {
 
     @Override
     public Expression visitSystemVariable(SystemVariableContext ctx) {
+        String name = ctx.identifier().getText();
+        SessionVariable sessionVariable = ConnectContext.get().getSessionVariable();
+        Literal literal = null;
         if (ctx.kind == null) {
-            return new VariableDesc(SetType.SESSION, ctx.identifier().getText());
+            literal = VariableMgr.getLiteral(sessionVariable, name, SetType.DEFAULT);
+        } else if (ctx.kind.getType() == DorisParser.SESSION) {
+            literal = VariableMgr.getLiteral(sessionVariable, name, SetType.SESSION);
+        } else if (ctx.kind.getType() == DorisParser.GLOBAL) {
+            literal = VariableMgr.getLiteral(sessionVariable, name, SetType.GLOBAL);
         }
-        switch (ctx.kind.getType()) {
-            case DorisParser.GLOBAL:
-                return new VariableDesc(SetType.GLOBAL, ctx.identifier().getText());
-            case DorisParser.SESSION:
-                return new VariableDesc(SetType.SESSION, ctx.identifier().getText());
-            default:
-                throw new ParseException("Unsupported system variable: " + ctx.getText(), ctx);
+        if (literal == null) {
+            throw new ParseException("Unsupported system variable: " + ctx.getText(), ctx);
+        }
+        if (!Strings.isNullOrEmpty(name) && VariableVarConverters.hasConverter(name)) {
+            try {
+                Preconditions.checkArgument(literal instanceof IntegerLikeLiteral);
+                IntegerLikeLiteral integerLikeLiteral = (IntegerLikeLiteral) literal;
+                literal = new StringLiteral(VariableVarConverters.decode(name, integerLikeLiteral.getLongValue()));
+            } catch (DdlException e) {
+                throw new ParseException(e.getMessage(), ctx);
+            }
         }
+        return literal;
     }
 
     @Override
@@ -607,7 +627,6 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> {
                 case DorisParser.AND:
                     return new And(left, right);
                 case DorisParser.OR:
-                case DorisParser.CONCAT_PIPE:
                     return new Or(left, right);
                 default:
                     throw new ParseException("Unsupported logical binary type: " + ctx.operator.getText(), ctx);
@@ -808,6 +827,19 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> {
                 + ", supported time unit: YEAR/MONTH/DAY/HOUR/MINUTE/SECOND", ctx);
     }
 
+    @Override
+    public Expression visitDoublePipes(DorisParser.DoublePipesContext ctx) {
+        return ParserUtils.withOrigin(ctx, () -> {
+            Expression left = getExpression(ctx.left);
+            Expression right = getExpression(ctx.right);
+            if (ConnectContext.get().getSessionVariable().getSqlMode() == SqlModeHelper.MODE_PIPES_AS_CONCAT) {
+                return new UnboundFunction("concat", Lists.newArrayList(left, right));
+            } else {
+                return new Or(left, right);
+            }
+        });
+    }
+
     /**
      * Create a value based [[CaseWhen]] expression. This has the following SQL form:
      * {{{
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rewrite/rules/FoldConstantRuleOnFE.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rewrite/rules/FoldConstantRuleOnFE.java
index c8e005e9e6..2ac4c7fe45 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rewrite/rules/FoldConstantRuleOnFE.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rewrite/rules/FoldConstantRuleOnFE.java
@@ -40,7 +40,6 @@ import org.apache.doris.nereids.trees.expressions.NullSafeEqual;
 import org.apache.doris.nereids.trees.expressions.Or;
 import org.apache.doris.nereids.trees.expressions.Slot;
 import org.apache.doris.nereids.trees.expressions.TimestampArithmetic;
-import org.apache.doris.nereids.trees.expressions.VariableDesc;
 import org.apache.doris.nereids.trees.expressions.WhenClause;
 import org.apache.doris.nereids.trees.expressions.functions.BoundFunction;
 import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
@@ -55,13 +54,10 @@ import org.apache.doris.nereids.trees.expressions.literal.BigIntLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.BooleanLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.Literal;
 import org.apache.doris.nereids.trees.expressions.literal.NullLiteral;
-import org.apache.doris.nereids.trees.expressions.literal.StringLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.VarcharLiteral;
 import org.apache.doris.nereids.types.BooleanType;
 import org.apache.doris.nereids.util.ExpressionUtils;
-import org.apache.doris.qe.VariableMgr;
 
-import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 
 import java.util.ArrayList;
@@ -348,13 +344,6 @@ public class FoldConstantRuleOnFE extends AbstractExpressionRewriteRule {
         return Literal.of(isNull.child().nullable());
     }
 
-    @Override
-    public Expression visitVariableDesc(VariableDesc variableDesc, ExpressionRewriteContext context) {
-        Preconditions.checkArgument(variableDesc.isSystemVariable());
-        return new StringLiteral(VariableMgr.getValue(context.connectContext.getSessionVariable(), variableDesc));
-
-    }
-
     @Override
     public Expression visitTimestampArithmetic(TimestampArithmetic arithmetic, ExpressionRewriteContext context) {
         return ExpressionEvaluator.INSTANCE.eval(arithmetic);
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/IntegerLikeLiteral.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/IntegerLikeLiteral.java
index c4e60e4c7a..9f8a08a00f 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/IntegerLikeLiteral.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/IntegerLikeLiteral.java
@@ -34,5 +34,9 @@ public abstract class IntegerLikeLiteral extends Literal {
         return getNumber().intValue();
     }
 
+    public long getLongValue() {
+        return getNumber().longValue();
+    }
+
     public abstract Number getNumber();
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java
index 1ec875a851..2c9390185d 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java
@@ -294,7 +294,7 @@ public class SessionVariable implements Serializable, Writable {
 
     // Set sqlMode to empty string
     @VariableMgr.VarAttr(name = SQL_MODE, needForward = true)
-    public long sqlMode = 0L;
+    public long sqlMode = SqlModeHelper.MODE_DEFAULT;
 
     @VariableMgr.VarAttr(name = RESOURCE_VARIABLE)
     public String resourceGroup = "normal";
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/SqlModeHelper.java b/fe/fe-core/src/main/java/org/apache/doris/qe/SqlModeHelper.java
index f014ebd631..7709ac6143 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/SqlModeHelper.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/SqlModeHelper.java
@@ -40,7 +40,8 @@ public class SqlModeHelper {
     //  of how they works and to be compatible with MySQL, so for now they are not
     //  really meaningful.
     /* Bits for different SQL MODE modes, you can add custom SQL MODE here */
-    public static final long MODE_REAL_AS_FLOAT = 1L;
+    /* When a new session is created, its sql mode is set to MODE_DEFAULT */
+    public static final long MODE_DEFAULT = 1L;
     public static final long MODE_PIPES_AS_CONCAT = 2L;
     public static final long MODE_ANSI_QUOTES = 4L;
     public static final long MODE_IGNORE_SPACE = 8L;
@@ -70,9 +71,8 @@ public class SqlModeHelper {
     public static final long MODE_TRADITIONAL = 1L << 27;
 
     public static final long MODE_LAST = 1L << 33;
+    public static final long MODE_REAL_AS_FLOAT = 1L << 34;
 
-    /* When a new session is create, its sql mode is set to MODE_DEFAULT */
-    public static final long MODE_DEFAULT = 0L;
 
     public static final long MODE_ALLOWED_MASK =
             (MODE_REAL_AS_FLOAT | MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES | MODE_IGNORE_SPACE | MODE_NOT_USED
@@ -80,7 +80,8 @@ public class SqlModeHelper {
                     | MODE_NO_AUTO_VALUE_ON_ZERO | MODE_NO_BACKSLASH_ESCAPES | MODE_STRICT_TRANS_TABLES
                     | MODE_STRICT_ALL_TABLES | MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | MODE_INVALID_DATES
                     | MODE_ERROR_FOR_DIVISION_BY_ZERO | MODE_HIGH_NOT_PRECEDENCE | MODE_NO_ENGINE_SUBSTITUTION
-                    | MODE_PAD_CHAR_TO_FULL_LENGTH | MODE_TRADITIONAL | MODE_ANSI | MODE_TIME_TRUNCATE_FRACTIONAL);
+                    | MODE_PAD_CHAR_TO_FULL_LENGTH | MODE_TRADITIONAL | MODE_ANSI | MODE_TIME_TRUNCATE_FRACTIONAL
+                    | MODE_DEFAULT);
 
     public static final long MODE_COMBINE_MASK = (MODE_ANSI | MODE_TRADITIONAL);
 
@@ -89,6 +90,7 @@ public class SqlModeHelper {
     private static final Map<String, Long> combineModeSet = Maps.newTreeMap(String.CASE_INSENSITIVE_ORDER);
 
     static {
+        sqlModeSet.put("DEFAULT", MODE_DEFAULT);
         sqlModeSet.put("REAL_AS_FLOAT", MODE_REAL_AS_FLOAT);
         sqlModeSet.put("PIPES_AS_CONCAT", MODE_PIPES_AS_CONCAT);
         sqlModeSet.put("ANSI_QUOTES", MODE_ANSI_QUOTES);
@@ -121,8 +123,8 @@ public class SqlModeHelper {
 
     // convert long type SQL MODE to string type that user can read
     public static String decode(Long sqlMode) throws DdlException {
-        // 0 parse to empty string
-        if (sqlMode == 0) {
+        if (sqlMode == MODE_DEFAULT) {
+            //For compatibility with older versions, return empty string
             return "";
         }
         if ((sqlMode & ~MODE_ALLOWED_MASK) != 0) {
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 b66a9b1df6..36468bc6f7 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
@@ -27,7 +27,7 @@ import org.apache.doris.common.DdlException;
 import org.apache.doris.common.ErrorCode;
 import org.apache.doris.common.ErrorReport;
 import org.apache.doris.common.PatternMatcher;
-import org.apache.doris.nereids.trees.expressions.VariableDesc;
+import org.apache.doris.nereids.trees.expressions.literal.Literal;
 import org.apache.doris.persist.GlobalVarPersistInfo;
 
 import com.google.common.base.Preconditions;
@@ -54,6 +54,7 @@ import java.util.Map;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
+import javax.annotation.Nullable;
 
 /**
  * Variable manager, merge session variable and global variable.
@@ -442,12 +443,50 @@ public class VariableMgr {
     }
 
     // For Nereids optimizer
-    public static String getValue(SessionVariable var, VariableDesc desc) throws RuntimeException {
+    public static @Nullable Literal getLiteral(SessionVariable var, String name, SetType setType) {
+        VarContext ctx = ctxByVarName.get(name);
+        if (ctx == null) {
+            return null;
+        }
+
+        if (setType == SetType.GLOBAL) {
+            rlock.lock();
+            try {
+                return getLiteral(ctx.getObj(), ctx.getField());
+            } finally {
+                rlock.unlock();
+            }
+        } else {
+            return getLiteral(var, ctx.getField());
+        }
+    }
+
+    private static Literal getLiteral(Object obj, Field field) {
         try {
-            return getValue(var, desc.getName(), desc.getSetType());
-        } catch (AnalysisException e) {
-            throw new RuntimeException(e);
+            switch (field.getType().getSimpleName()) {
+                case "boolean":
+                    return Literal.of(field.getBoolean(obj));
+                case "byte":
+                    return Literal.of(field.getByte(obj));
+                case "short":
+                    return Literal.of(field.getShort(obj));
+                case "int":
+                    return Literal.of(field.getInt(obj));
+                case "long":
+                    return Literal.of(field.getLong(obj));
+                case "float":
+                    return Literal.of(field.getFloat(obj));
+                case "double":
+                    return Literal.of(field.getDouble(obj));
+                case "String":
+                    return Literal.of((String) field.get(obj));
+                default:
+                    return Literal.of("");
+            }
+        } catch (IllegalAccessException e) {
+            LOG.warn("Access failed.", e);
         }
+        return Literal.of("");
     }
 
     private static String getValue(Object obj, Field field) {
diff --git a/regression-test/suites/nereids_syntax_p0/expression.groovy b/regression-test/suites/nereids_syntax_p0/expression.groovy
index 59c373ba0b..05eab65a3e 100644
--- a/regression-test/suites/nereids_syntax_p0/expression.groovy
+++ b/regression-test/suites/nereids_syntax_p0/expression.groovy
@@ -28,4 +28,10 @@ suite("nereids_syntax_expression_test") {
         sql "select true or false, true || false"
         result([[true, true]])
     }
+
+    sql """ SET sql_mode = "PIPES_AS_CONCAT" """
+    test {
+        sql "select @@session.sql_mode, 1 || 2"
+        result([["PIPES_AS_CONCAT", "12"]])
+    }
 }
diff --git a/regression-test/suites/nereids_syntax_p0/system_var.groovy b/regression-test/suites/nereids_syntax_p0/system_var.groovy
index 3ae1580b8a..3a3714e8c8 100644
--- a/regression-test/suites/nereids_syntax_p0/system_var.groovy
+++ b/regression-test/suites/nereids_syntax_p0/system_var.groovy
@@ -44,6 +44,6 @@ suite("nereids_sys_var") {
     sql "select @@session.time_zone"
     test {
         sql "select @@session.enable_nereids_planner"
-        result ([["true"]])
+        result ([[true]])
     }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org