Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Fix](Nereids) fix append_trailing_char_if_absent function return null (#40820) #41160

Open
wants to merge 2 commits into
base: branch-2.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,10 @@ public class FoldConstantRuleOnBE extends AbstractExpressionRewriteRule {

@Override
public Expression rewrite(Expression expr, ExpressionRewriteContext ctx) {
Expression expression = FoldConstantRuleOnFE.INSTANCE.rewrite(expr, ctx);
if(ctx.cascadesContext.getConnectContext().getSessionVariable().isDebugSkipFoldConstant()) {
return null;
}
Expression expression = FoldConstantRuleOnFE.INSTANCE.rewrite(expr, ctx);
return foldByBE(expression, ctx);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
import org.apache.doris.nereids.trees.expressions.literal.FloatLiteral;
import org.apache.doris.nereids.trees.expressions.literal.IntegerLiteral;
import org.apache.doris.nereids.trees.expressions.literal.LargeIntLiteral;
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.StringLikeLiteral;
import org.apache.doris.nereids.trees.expressions.literal.TinyIntLiteral;
import org.apache.doris.nereids.trees.expressions.literal.VarcharLiteral;

Expand Down Expand Up @@ -91,13 +93,19 @@ public static Expression acos(DoubleLiteral literal) {
return new DoubleLiteral(Math.acos(literal.getValue()));
}

@ExecFunction(name = "append_trailing_if_char_absent", argTypes = {"VARCHAR", "VARCHAR"}, returnType = "VARCHAR")
public static Expression appendTrailingIfCharAbsent(VarcharLiteral literal, VarcharLiteral chr) {
if (literal.getValue().length() != 1) {
return null;
/**
* append_trailing_char_if_absent function
*/
@ExecFunction(name = "append_trailing_char_if_absent", argTypes = {"VARCHAR", "VARCHAR"}, returnType = "VARCHAR")
public static Expression appendTrailingIfCharAbsent(StringLikeLiteral literal, StringLikeLiteral chr) {
if (chr.getStringValue().length() != 1) {
return new NullLiteral(literal.getDataType());
}
if (literal.getStringValue().endsWith(chr.getStringValue())) {
return literal;
} else {
return new VarcharLiteral(literal.getStringValue() + chr.getStringValue());
}
return literal.getValue().endsWith(chr.getValue()) ? literal
: new VarcharLiteral(literal.getValue() + chr.getValue());
}

@ExecFunction(name = "e", argTypes = {}, returnType = "DOUBLE")
Expand Down
13 changes: 13 additions & 0 deletions fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ public class SessionVariable implements Serializable, Writable {
public static final String PREFER_JOIN_METHOD = "prefer_join_method";

public static final String ENABLE_FOLD_CONSTANT_BY_BE = "enable_fold_constant_by_be";
public static final String DEBUG_SKIP_FOLD_CONSTANT = "debug_skip_fold_constant";

public static final String ENABLE_ODBC_TRANSCATION = "enable_odbc_transcation";
public static final String ENABLE_SQL_CACHE = "enable_sql_cache";
public static final String ENABLE_PARTITION_CACHE = "enable_partition_cache";
Expand Down Expand Up @@ -807,6 +809,9 @@ public class SessionVariable implements Serializable, Writable {
@VariableMgr.VarAttr(name = ENABLE_FOLD_CONSTANT_BY_BE, fuzzy = true)
private boolean enableFoldConstantByBe = false;

@VariableMgr.VarAttr(name = DEBUG_SKIP_FOLD_CONSTANT)
public boolean debugSkipFoldConstant = false;

@VariableMgr.VarAttr(name = RUNTIME_FILTER_MODE, needForward = true)
private String runtimeFilterMode = "GLOBAL";

Expand Down Expand Up @@ -1933,6 +1938,10 @@ public boolean isEnableFoldConstantByBe() {
return enableFoldConstantByBe;
}

public boolean isDebugSkipFoldConstant() {
return debugSkipFoldConstant;
}

public boolean isEnableNereidsDML() {
return enableNereidsDML;
}
Expand All @@ -1941,6 +1950,10 @@ public void setEnableFoldConstantByBe(boolean foldConstantByBe) {
this.enableFoldConstantByBe = foldConstantByBe;
}

public void setDebugSkipFoldConstant(boolean debugSkipFoldConstant) {
this.debugSkipFoldConstant = debugSkipFoldConstant;
}

public int getParallelExecInstanceNum() {
ConnectContext connectContext = ConnectContext.get();
if (connectContext != null && connectContext.getEnv() != null && connectContext.getEnv().getAuth() != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1221,7 +1221,8 @@ private void analyzeAndGenerateQueryPlan(TQueryOptions tQueryOptions) throws Use
if (parsedStmt instanceof QueryStmt || parsedStmt instanceof InsertStmt) {
ExprRewriter rewriter = analyzer.getExprRewriter();
rewriter.reset();
if (context.getSessionVariable().isEnableFoldConstantByBe()) {
if (context.getSessionVariable().isEnableFoldConstantByBe()
&& !context.getSessionVariable().isDebugSkipFoldConstant()) {
// fold constant expr
parsedStmt.foldConstant(rewriter, tQueryOptions);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -947,6 +947,20 @@ class Suite implements GroovyInterceptable {
return debugPoint
}

void testFoldConst(String foldSql) {
String openFoldConstant = "set debug_skip_fold_constant=false";
sql(openFoldConstant)
logger.info(foldSql)
List<List<Object>> resultByFoldConstant = sql(foldSql)
logger.info("result by fold constant: " + resultByFoldConstant.toString())
String closeFoldConstant = "set debug_skip_fold_constant=true";
sql(closeFoldConstant)
logger.info(foldSql)
List<List<Object>> resultExpected = sql(foldSql)
logger.info("result expected: " + resultExpected.toString())
Assert.assertEquals(resultExpected, resultByFoldConstant)
}

boolean isCloudMode() {
return false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,4 +161,90 @@ suite("test_fold_constant_by_fe") {
res = sql """explain select "12" like '%123%'"""
assertTrue(res.contains("like"))

// Normal Usage Test Cases

// Test Case 1: Append missing trailing character
testFoldConst("select append_trailing_char_if_absent('hello', '!')")
// Expected Output: 'hello!'

// Test Case 2: Trailing character already present
testFoldConst("select append_trailing_char_if_absent('hello!', '!')")
// Expected Output: 'hello!'

// Test Case 3: Append trailing space
testFoldConst("select append_trailing_char_if_absent('hello', ' ')")
// Expected Output: 'hello '

// Test Case 4: Empty string input
testFoldConst("select append_trailing_char_if_absent('', '!')")
// Expected Output: '!'

// Test Case 5: Append different character
testFoldConst("select append_trailing_char_if_absent('hello', '?')")
// Expected Output: 'hello?'

// Test Case 6: String ends with a different character
testFoldConst("select append_trailing_char_if_absent('hello?', '!')")
// Expected Output: 'hello?!'

// Edge and Unusual Usage Test Cases

// Test Case 7: Input is NULL
testFoldConst("select append_trailing_char_if_absent(NULL, '!')")
// Expected Output: NULL

// Test Case 8: Trailing character is NULL
testFoldConst("select append_trailing_char_if_absent('hello', NULL)")
// Expected Output: NULL

// Test Case 9: Empty trailing character
testFoldConst("select append_trailing_char_if_absent('hello', '')")
// Expected Output: Error or no change depending on implementation

// Test Case 10: Trailing character is more than 1 character long
testFoldConst("select append_trailing_char_if_absent('hello', 'ab')")
// Expected Output: Error

// Test Case 11: Input string is a number
testFoldConst("select append_trailing_char_if_absent(12345, '!')")
// Expected Output: Error or '12345!'

// Test Case 12: Trailing character is a number
testFoldConst("select append_trailing_char_if_absent('hello', '1')")
// Expected Output: 'hello1'

// Test Case 13: Input is a single character
testFoldConst("select append_trailing_char_if_absent('h', '!')")
// Expected Output: 'h!'

// Test Case 14: Unicode character as input and trailing character
testFoldConst("select append_trailing_char_if_absent('こんにちは', '!')")
// Expected Output: 'こんにちは!'

// Test Case 15: Multibyte character as trailing character
testFoldConst("select append_trailing_char_if_absent('hello', '😊')")
// Expected Output: 'hello😊'

// Test Case 16: Long string input
testFoldConst("select append_trailing_char_if_absent('This is a very long string', '.')")
// Expected Output: 'This is a very long string.'

// Error Handling Test Cases

// Test Case 17: Invalid trailing character data type (numeric)
testFoldConst("select append_trailing_char_if_absent('hello', 1)")
// Expected Output: Error

// Test Case 18: Invalid input data type (integer)
testFoldConst("select append_trailing_char_if_absent(12345, '!')")
// Expected Output: Error or '12345!'

// Test Case 19: Non-ASCII characters
testFoldConst("select append_trailing_char_if_absent('Привет', '!')")
// Expected Output: 'Привет!'

// Test Case 20: Trailing character with whitespace
testFoldConst("select append_trailing_char_if_absent('hello', ' ')")
// Expected Output: 'hello '

}
Loading