[MySQL Compatibility 1/4][Bug] Fix bug that set sql_mode with concat() function failed (#4359)

Support `set sql_mode = concat(@@sql_mode, "STRICT_TRANS_TABLES");`
This commit is contained in:
Mingyu Chen
2020-08-26 10:28:25 +08:00
committed by GitHub
parent b1c7841c20
commit 0040153c51
4 changed files with 113 additions and 5 deletions

View File

@ -22,6 +22,8 @@ import org.apache.doris.catalog.Function;
import org.apache.doris.catalog.ScalarType;
import org.apache.doris.catalog.Type;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.qe.ConnectContext;
import org.apache.doris.qe.VariableMgr;
import org.apache.doris.rewrite.FEFunction;
import org.apache.doris.rewrite.FEFunctions;
@ -56,18 +58,18 @@ public enum ExpressionFunctions {
public Expr evalExpr(Expr constExpr) {
// Function's arg are all LiteralExpr.
for (Expr child : constExpr.getChildren()) {
if (!(child instanceof LiteralExpr)) {
if (!(child instanceof LiteralExpr) && !(child instanceof SysVariableDesc)) {
return constExpr;
}
}
if (constExpr instanceof ArithmeticExpr
|| constExpr instanceof FunctionCallExpr
|| constExpr instanceof FunctionCallExpr
|| constExpr instanceof TimestampArithmeticExpr) {
Function fn = constExpr.getFn();
Preconditions.checkNotNull(fn, "Expr's fn can't be null.");
// return NullLiteral directly iff:
// 1. Not UDF
// 2. Not in NonNullResultWithNullParamFunctions
@ -96,6 +98,14 @@ public enum ExpressionFunctions {
return constExpr;
}
}
} else if (constExpr instanceof SysVariableDesc) {
try {
VariableMgr.fillValue(ConnectContext.get().getSessionVariable(), (SysVariableDesc) constExpr);
return ((SysVariableDesc) constExpr).getLiteralExpr();
} catch (AnalysisException e) {
LOG.warn("failed to get session variable value: " + ((SysVariableDesc) constExpr).getName());
return constExpr;
}
}
return constExpr;
}

View File

@ -17,7 +17,6 @@
package org.apache.doris.analysis;
import com.google.common.base.Strings;
import org.apache.doris.catalog.Type;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.DdlException;
@ -32,6 +31,8 @@ import org.apache.doris.thrift.TFloatLiteral;
import org.apache.doris.thrift.TIntLiteral;
import org.apache.doris.thrift.TStringLiteral;
import com.google.common.base.Strings;
// System variable
// Converted to StringLiteral in analyze, if this variable is not exist, throw AnalysisException.
public class SysVariableDesc extends Expr {
@ -42,6 +43,8 @@ public class SysVariableDesc extends Expr {
private double floatValue;
private String strValue;
private LiteralExpr literalExpr;
public SysVariableDesc(String name) {
this(name, SetType.SESSION);
}
@ -89,18 +92,48 @@ public class SysVariableDesc extends Expr {
public void setBoolValue(boolean value) {
this.boolValue = value;
this.literalExpr = new BoolLiteral(value);
}
public void setIntValue(long value) {
this.intValue = value;
this.literalExpr = new IntLiteral(value);
}
public void setFloatValue(double value) {
this.floatValue = value;
this.literalExpr = new FloatLiteral(value);
}
public void setStringValue(String value) {
this.strValue = value;
this.literalExpr = new StringLiteral(value);
}
public Expr getLiteralExpr() {
return this.literalExpr;
}
@Override
public Expr getResultValue() throws AnalysisException {
Expr expr = super.getResultValue();
if (!Strings.isNullOrEmpty(name) && name.equalsIgnoreCase(SessionVariable.SQL_MODE)) {
// SQL_MODE is a special variable. Its type is int, but it is usually set using a string.
// Such as `set sql_mode = concat(@@sql_mode, "STRICT_TRANS_TABLES");`
// So we return the string type here so that it can correctly match the subsequent function signature.
// We will convert the string to int in VariableMgr.
try {
return new StringLiteral(SqlModeHelper.decode(intValue));
} catch (DdlException e) {
throw new AnalysisException(e.getMessage());
}
}
return expr;
}
@Override
protected boolean isConstantImpl() {
return true;
}
@Override

View File

@ -0,0 +1,63 @@
// 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.
package org.apache.doris.analysis;
import org.apache.doris.qe.ConnectContext;
import org.apache.doris.qe.SqlModeHelper;
import org.apache.doris.qe.StmtExecutor;
import org.apache.doris.utframe.UtFrameUtils;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import java.util.UUID;
public class SetVariableTest {
// use a unique dir so that it won't be conflict with other unit test which
// may also start a Mocked Frontend
private static String runningDir = "fe/mocked/QueryPlanTest/" + UUID.randomUUID().toString() + "/";
private static ConnectContext connectContext;
@BeforeClass
public static void beforeClass() throws Exception {
UtFrameUtils.createMinDorisCluster(runningDir);
// create connect context
connectContext = UtFrameUtils.createDefaultCtx();
}
@Test
public void testSqlMode() throws Exception {
String setStr = "set sql_mode = concat(@@sql_mode, 'STRICT_TRANS_TABLES');";
connectContext.getState().reset();
StmtExecutor stmtExecutor = new StmtExecutor(connectContext, setStr);
stmtExecutor.execute();
Assert.assertEquals("STRICT_TRANS_TABLES",
SqlModeHelper.decode(connectContext.getSessionVariable().getSqlMode()));
}
@Test
public void testExecMemLimit() throws Exception {
String setStr = "set exec_mem_limit = @@exec_mem_limit * 10";
connectContext.getState().reset();
StmtExecutor stmtExecutor = new StmtExecutor(connectContext, setStr);
stmtExecutor.execute();
Assert.assertEquals(21474836480L, connectContext.getSessionVariable().getMaxExecMemByte());
}
}

View File

@ -48,6 +48,8 @@ import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import com.google.common.collect.Lists;
import java.io.File;
import java.util.List;
import java.util.UUID;